内容简介:Java语言的重写与JVM的重写并不一致,当在Java语言中为重写而在JVM中为非重写,编译器会通过生成
Java语言的重写与JVM的重写并不一致,当在 Java 语言中为重写而在JVM中为非重写,编译器会通过生成 桥接方法 来实现Java中的重写语义
桥接方法 – 返回类型
Java代码
@Slf4j public class Father { public Number work() { return 1.0; } public static void main(String[] args) { Father father = new Son(); // 实际调用的是桥接方法 Number work = father.work(); log.info("{}", work); } } class Son extends Father { @Override public Double work() { return 2.0; } }
字节码
$ javap -v -c Son public java.lang.Double work(); descriptor: ()Ljava/lang/Double; flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: ldc2_w #2 // double 2.0d 3: invokestatic #4 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double; 6: areturn LineNumberTable: line 21: 0 LocalVariableTable: Start Length Slot Name Signature 0 7 0 this Lme/zhongmingmao/basic/bridge/return_type/Son; // 桥接办法 public java.lang.Number work(); descriptor: ()Ljava/lang/Number; // ACC_BRIDGE:桥接方法;ACC_SYNTHETIC:编译器自动生成 flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC Code: stack=1, locals=1, args_size=1 0: aload_0 // 调用Son本身重写的方法 1: invokevirtual #5 // Method work:()Ljava/lang/Double; 4: areturn LineNumberTable: line 18: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lme/zhongmingmao/basic/bridge/return_type/Son;
-
如果没有桥接办法,对于Java语言是重写的,但对于JVM来说却不是重写的
- 只有当两个方法的 参数类型 和 返回类型 一致,JVM才会判定为重写
- Java编译器会在Son的字节码中 自动生成一个桥接方法 来保证重写语义
翻译桥接方法
public Number work() { return this.work(); }
调用桥接办法
- 编译器通过插入 桥接办法 来保证重写的语义
- JVM通过 方法描述符 (参数类型+返回类型)定位到具体的方法
Father father = new Son(); // 实际调用的是桥接方法 Number work = father.work(); log.info("{}", work);
桥接方法 – 泛型
Java代码
public interface Father { void work(); static void main(String[] args) { Job job = new Doctor(); // 调用实际的方法 job.work(new Son()); // 调用桥接方法,有checkcast指令,抛出ClassCastException job.work(new Daughter()); } } class Son implements Father { @Override public void work() { } } class Daughter implements Father { @Override public void work() { } } abstract class Job<T extends Father> { protected void work(T father) { father.work(); } } class Doctor extends Job<Son> { @Override public void work(Son son) { super.work(son); } } class Nurse extends Job<Daughter> { @Override public void work(Daughter daughter) { super.work(daughter); } }
字节码
$ javap -v -c Job protected void work(T); // Java是伪泛型,会进行类型擦除 // 因此泛型T被换成Father,方法签名为protected void work(Father father) descriptor: (Lme/zhongmingmao/basic/bridge/generic/Father;)V flags: ACC_PROTECTED Code: stack=1, locals=2, args_size=2 0: aload_1 // 调用接口方法 1: invokeinterface #2, 1 // InterfaceMethod me/zhongmingmao/basic/bridge/generic/Father.work:()V 6: return LineNumberTable: line 27: 0 line 28: 6 LocalVariableTable: Start Length Slot Name Signature 0 7 0 this Lme/zhongmingmao/basic/bridge/generic/Job; 0 7 1 father Lme/zhongmingmao/basic/bridge/generic/Father; LocalVariableTypeTable: Start Length Slot Name Signature 0 7 0 this Lme/zhongmingmao/basic/bridge/generic/Job<TT;>; 0 7 1 father TT; Signature: #20 // (TT;)V
$ javap -v -c Doctor public void work(me.zhongmingmao.basic.bridge.generic.Son); descriptor: (Lme/zhongmingmao/basic/bridge/generic/Son;)V flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: invokespecial #2 // Method me/zhongmingmao/basic/bridge/generic/Job.work:(Lme/zhongmingmao/basic/bridge/generic/Father;)V 5: return LineNumberTable: line 34: 0 line 35: 5 LocalVariableTable: Start Length Slot Name Signature 0 6 0 this Lme/zhongmingmao/basic/bridge/generic/Doctor; 0 6 1 son Lme/zhongmingmao/basic/bridge/generic/Son; // 桥接方法 public void work(me.zhongmingmao.basic.bridge.generic.Father); descriptor: (Lme/zhongmingmao/basic/bridge/generic/Father;)V flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 // 类型校验,必须为Son类型 2: checkcast #3 // class me/zhongmingmao/basic/bridge/generic/Son // 调用Doctor本身重写的方法(非私有实例方法) 5: invokevirtual #4 // Method work:(Lme/zhongmingmao/basic/bridge/generic/Son;)V 8: return LineNumberTable: line 31: 0 LocalVariableTable: Start Length Slot Name Signature 0 9 0 this Lme/zhongmingmao/basic/bridge/generic/Doctor;
翻译桥接办法
public void work(Father father){ // 强制类型转换 super.work((Son) father); }
调用桥接办法
Job job = new Doctor(); // 调用实际的方法 job.work(new Son()); // 调用桥接方法,有checkcast指令,抛出ClassCastException job.work(new Daughter());
转载请注明出处:http://zhongmingmao.me/2018/12/18/jvm-basic-bridge-method/
访问原文「桥接方法」获取最佳阅读体验并参与讨论
以上所述就是小编给大家介绍的《桥接方法》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
为什么中国没出Facebook
谢文 / 凤凰出版社 / 2011-7-1 / 39.80元
《为什么中国没出Facebook》对互联网的游戏规则、市场、格局、模式及发展趋势等多方面进行了阐述,既勾画出了理想中的互联网生态及其本质,又联系中国实际,探讨了中国互联网行业的未来发展。《为什么中国没出Facebook》提出了在互联网成事应该符合的8条原则,比较了Facebook、MySpace、Twitter三种创新模式,指出了Web2.0平台时代新浪、腾讯、百度、搜狐等互联网巨头的未来方向,也......一起来看看 《为什么中国没出Facebook》 这本书的介绍吧!