JVM学习笔记——Java和JVM在重写语义上的差异

JVM学习笔记——Java和JVM在重写语义上的差异

Java和JVM中识别方法的差异

Java在其语义中,通过类名方法名方法的参数类型唯一标识方法。

JVM通过类名方法名方法描述符(方法的参数类型以及方法的返回类型)唯一标识方法。

差异显而易见。在Java中,若同类、同方法名以及方法参数类型相同,则无法通过编译;而在JVM中还可以通过方法的返回类型区分方法。

Java和JVM中重写的差异

重写的判定基于Java和JVM中识别方法的方式,因此在Java和JVM中的重写语义不相同。如下述代码中,在Java中,DifferenceInOverriding中"invoke"是父类中"invoke"的重写方法,但在JVM中则相反。

public class DifferenceInOverridingSuper {
    public Number invoke() {
        return null;
    }
}

public class DifferenceInOverriding extends DifferenceInOverridingSuper {
    @Override
    public Float invoke() {
        return null;
    }
}

Java和JVM的重写语义不一致,为了统一差异,编译器生成桥接方法来实现Java中的重写语义。为证实这一论点,可编译上述代码,查看桥接方法:

# 编译
javac DifferenceInOverriding.java
# 反编译
javap -v DifferenceInOverriding > difference
vi difference

可以看到两个标明为invoke()的方法,但其中为一个为桥接方法:

  public java.lang.Float invoke();
    descriptor: ()Ljava/lang/Float;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aconst_null
         1: areturn
      LineNumberTable:
        line 4: 0

  public java.lang.Number invoke();
    descriptor: ()Ljava/lang/Number;
    flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC // ACC_BRIDGE即说明为桥接方法
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokevirtual #2                  // Method invoke:()Ljava/lang/Float;
         4: areturn
      LineNumberTable:
        line 1: 0

可以看到一行"1: invokevirtual #2 // Method invoke:()Ljava/lang/Float;",为了证实此处的注释,可翻到该文件头部的常量池(摘取部分):

Constant pool:
   #1 = Methodref          #4.#14         // DifferenceInOverridingSuper."<init>":()V
   #2 = Methodref          #3.#15         // DifferenceInOverriding.invoke:()Ljava/lang/Float;
   #3 = Class              #16            // DifferenceInOverriding
   #9 = Utf8               invoke
   #10 = Utf8               ()Ljava/lang/Float;
   #15 = NameAndType        #9:#10         // invoke:()Ljava/lang/Float;
   #16 = Utf8               DifferenceInOverriding

可以看到这里的“#2”符号引用指向了"#3.#15",解析得调用了返回Float类型的DifferenceInOverriding#invoke,可理解为:

return this.invoke();

总结

Java和JVM中重写的前提是子类定义了父类中非私有非静态的同名方法。除了Java中的类名方法名方法的参数类型,JVM还可以通过方法返回类型来标识一个方法,由此Java和JVM重写语义不一致,编译器生成桥接方法来统一语义上的差异。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值