内容简介: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/
访问原文「桥接方法」获取最佳阅读体验并参与讨论
以上所述就是小编给大家介绍的《桥接方法》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
锋利的jQuery
单东林、张晓菲、魏然 / 人民邮电出版社 / 2012-7-1 / 49.00元
《锋利的jQuery(第2版)》循序渐进地对jQuery的各种函数和方法调用进行了介绍,读者可以系统地掌握jQuery的选择器、DOM操作、事件和动画、AJAX应用、插件、jQuery Mobile、jQuery各个版本变化、jQuery性能优化和技巧等知识点,并结合每个章节后面的案例演示进行练习,达到掌握核心知识点的目的。 为使读者更好地进行开发实践,《锋利的jQuery(第2版)》的第8......一起来看看 《锋利的jQuery》 这本书的介绍吧!