1

1.为什么需要bridgeMethod

  • Java(Java源语言)与 JVM 虚拟机 存在语义上的差异,JavaOverride方法指的是方法参数和方法名称完全一致.这样的操作称为Override.如果方法参数类型不一致(包括参数类型,或者参数的顺序不一致),这样的操作称为Overloading.两者在Java中的判断都不包括返回值类型return type,即返回值类型与两者无关
  • JVM中,对于同个方法名,不同的parameter typereturn type 都可以看作Override操作,因为在JVM采用Full-Signature(全方法签名)来校验一个方法的合法性,全体包括method name,parameter type,return type
  • 综上,JavaJVMOverride的语义规则不一致.为了去除语义冲突,同时又不用修改JVM实现的需求下,bridgeMethod应运而生,可以把它看作我们web开发中常见的中间件(中间过程处理)来理解.

2.打破常规

  • 能生成Java字节码的方式有很多 不止在编译器中 如Idea,eclipse等 在编译器中 相同方法名称 不同的返回值编译是不能通过的 但是我们可以通过其他方式来生成符合场景的字节码文件
  • JVMJava语义不一样,举个生活中的例子,这就好比方言和普通话,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实现了父类SuperClasschifan()方法,相同的方法名,相同的方法参数列表,相同的方法参数类型,即在Java中,这已经完成了Override重写的语义定义.但是在JVM中,这并不是能够认可的Override行为.有语义冲突.所以创造了一个bridgeMethod方法
  • 本人目前学习到的所有博客,对Java版本有特别印象(学习其他大佬的文章中经常提到的版本)的有3个.从低到高分别是Java5,Java7,Java8,本文中涉及到的技术点主要是Java5Java 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点,我总以为JavaJVM之间语义是一致的,或许更准确的说,我一直都不知道JavaJVM存在语义差异.所以看一些质量不高的博客后总有一种似懂非懂的感觉.学技术应该知其然更知其所以然.如果有问题,请大佬们指正.帮助我进步.谢谢.


北上求道
118 声望6 粉丝

江湖小虾