Java语言的重写与JVM的重写并不一致,当在Java语言中为重写而在JVM中为非重写,编译器会通过生成 桥接方法 来实现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;
public Number work() {
return this.work();
}
Father father = new Son();
// 实际调用的是桥接方法
Number work = father.work();
log.info("{}", work);
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/
访问原文「桥接方法」获取最佳阅读体验并参与讨论