1.为什么需要bridgeMethod
-
Java
(Java源语言)与JVM
虚拟机 存在语义上的差异,Java
中Override
方法指的是方法参数和方法名称完全一致.这样的操作称为Override
.如果方法参数类型不一致(包括参数类型,或者参数的顺序不一致),这样的操作称为Overloading
.两者在Java
中的判断都不包括返回值类型return type
,即返回值类型与两者无关 -
JVM中
,对于同个方法名,不同的parameter type
与return type
都可以看作Override
操作,因为在JVM采用Full-Signature
(全方法签名)来校验一个方法的合法性,全体包括method name,parameter type,return type
- 综上,
Java
与JVM
对Override
的语义规则不一致.为了去除语义冲突,同时又不用修改JVM
实现的需求下,bridgeMethod
应运而生,可以把它看作我们web
开发中常见的中间件(中间过程处理)来理解.
2.打破常规
- 能生成
Java
字节码的方式有很多 不止在编译器中 如Idea,eclipse等 在编译器中 相同方法名称 不同的返回值编译是不能通过的 但是我们可以通过其他方式来生成符合场景的字节码文件 -
JVM
与Java
语义不一样,举个生活中的例子,这就好比方言和普通话,Java
就是四川方言,JVM
就是普通话,四川话:'你吃饭了没得,幺儿',普通话:'你吃饭了吗,儿子 or 女儿'(注意这里的差别).四川方言中,"幺儿"可以是儿子和女儿的统称,这就对应Java
中相同method name
不区分return type
.但是在普通话中,需要指明"儿子"或者是"女儿". 大家都是一个意思,只不过表达方式不一样.普通话是中国话的标准,规则就更严格和细致.为了将方言翻译成普通话能理解的意思,就要去除两者的语义差异,这就是bridgeMethod
的意义.
3.API相关
- 根据
reflect
的相关方法,我们可以获取一个Object Class
的全部定义,包括属性,方法名等等. - 根据常规
class.getDeclaredMethod(String name,Class<?>...paramterTypes)
可以根据方法名称和参数类型获取class
中的方法,但是这个方法对相同方法名不同返回值无效. - 可以通过
class.getDeclaredMethod()
获取全部的方法 -
MethodHandles.Lookup
提供了更丰富更灵活的API,可以根据method name,paramter type,return type
的限定条件获取一个方法
4.代码实现
一个接口SuperClass
public interface SuperClass<T>{
T chifan();
}
一个实现类SubClass
public class SubClass<String> implements SuperClass{
@Override
public String chifan(){
return "幺儿";
}
}
在JVM
中实现类SubClass
的代码如下
public class SubClass<String> implements SuperClass{
@Override
public String chifan(){
return "幺儿";//这里是Java方言 幺儿的统称 String类型 是"男孩","女孩" 都行
}
@Override
public Object chifan(){
return (String)"幺儿";//bridgeMethod 将"幺儿"指定为String类型,"男孩",或者是"女孩"
}
}
- 在
Java
中,子类SubClass
实现了父类SuperClass
的chifan()
方法,相同的方法名,相同的方法参数列表,相同的方法参数类型,即在Java
中,这已经完成了Override
重写的语义定义.但是在JVM
中,这并不是能够认可的Override
行为.有语义冲突.所以创造了一个bridgeMethod
方法 - 本人目前学习到的所有博客,对
Java
版本有特别印象(学习其他大佬的文章中经常提到的版本)的有3个.从低到高分别是Java5
,Java7
,Java8
,本文中涉及到的技术点主要是Java5
即Java 1.5
以后出现的.所以我们来谈下Java5
的版本特性
5.追根溯源 Java5特性
-
Java5 support covaraint return type
支持可变返回类型,在Java5
之前.子类实现的方法名称,方法参数,返回类型都要相同,才叫method Override
.具体可以看下篇文章https://blogs.oracle.com/sund...
-
Java5
以后,只要子类实现方法的返回类型是父类方法返回类型的子类,也可以认作是Override
. -
Java5
以后支持范型,范型的出现是为了减少类型转换异常.将一些运行时才能暴露的问题提前在编译时暴露.可以参见下面的代码
List list=new ArrayList();
list.add("wcl");
list.add(2.50);
上面的代码没有问题,但是并不好,因为指代不明.在Idea中会出现类型未检查的异常.接着来举例.
有一个女老师,带小学生们出去春游.
老师说:"孩子们,老师带你们上厕所,走吧走吧".(规则指定 女老师只能带小女孩去上厕所).可是因为"孩子们"这样的称呼,指代不明,我这样呆萌的小男孩也会跟着老师去上厕所,那这就尴尬了,就会有误入女厕的情况发生.
为了避免这种情况发生.范型出现了.如下
List<String> list=new ArrayList();
list.add("wcl");
list.add(2.50);// error
范型的作用如上所示 就像是女老师的话变为
老师说:"女孩子们,老师带你们上厕所,走吧走吧".这时呆萌的小男孩就不会跟着老师去了.去了就要被教育
本文的bridgeMethod
也可以用上面的例子举例.
"孩子们,老师带你们上厕所" 这是Java
中的语义
"孩子们,老师带你们上男厕所"这是JVM
中的语义
看起来 范型的使用就是规则限定前置 bridgeMethod
的使用 就是规则限定后置 两者有异曲同工之妙
6.结语
最近学习大佬的 SpringMVC:源代码分析与实现 里面的 BridgeMethodResolver
然后学习了bridgeMethod
以上都是本人看博客的一些总结 然后用自认为容易理解的形式 和 本人学习过程中模糊点的解释 .特别是第2点,我总以为Java
与JVM
之间语义是一致的,或许更准确的说,我一直都不知道Java
与JVM
存在语义差异.所以看一些质量不高的博客后总有一种似懂非懂的感觉.学技术应该知其然更知其所以然.如果有问题,请大佬们指正.帮助我进步.谢谢.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。