【问题标题】:Is it possible to define method binding type by bytecode?是否可以通过字节码定义方法绑定类型?
【发布时间】:2017-07-13 02:03:48
【问题描述】:

来自以下来源:

https://www.amazon.com/Java-Complete-Reference-Herbert-Schildt/dp/0071808558

第 8 章:使用 final 和继承

http://javarevisited.blogspot.com.by/2012/03/what-is-static-and-dynamic-binding-in.html

Static Vs. Dynamic Binding in Java

对于私有、静态、最终方法,早期(静态)方法绑定应该 被使用

。所以我创建了一个小测试

class MethodRefDemo2
{
  public static void main( String args[] )
  {
    BindingTest bindingTest = new BindingTest();
    bindingTest.printEarly();
    bindingTest.printLate();
  }
}

class BindingTest
{
  private String early = "static";
  private String late = "dynamic";

  final String printEarly()
  {
    return early;
  }

  String printLate()
  {
    return late;
  }
}

所以我认为,这两种方法应该有不同的绑定类型。检查字节码:

 public static main([Ljava/lang/String;)V
   L0
    LINENUMBER 8 L0
    NEW spring/BindingTest
    DUP
    INVOKESPECIAL spring/BindingTest.<init> ()V
    ASTORE 1
   L1
    LINENUMBER 9 L1
    ALOAD 1
    INVOKEVIRTUAL spring/BindingTest.printEarly ()Ljava/lang/String;
    POP
   L2
    LINENUMBER 10 L2
    ALOAD 1
    INVOKEVIRTUAL spring/BindingTest.printLate ()Ljava/lang/String;
    POP
   L3
    LINENUMBER 11 L3
    RETURN
   L4
    LOCALVARIABLE args [Ljava/lang/String; L0 L4 0
    LOCALVARIABLE bindingTest Lspring/BindingTest; L1 L4 1
    MAXSTACK = 2
    MAXLOCALS = 2

在这里我看到两个 INVOKEVIRTUAL 指令。那么有没有办法确定类字节码使用了什么样的绑定呢?如果没有,我如何确定绑定类型?

【问题讨论】:

    标签: java binding bytecode


    【解决方案1】:

    “来自 java 规范”这句话具有误导性,因为没有多个规范,所以只有 the Java specification 不包含引用的声明。

    术语“早期绑定”和“后期绑定”不足以描述 Java 方法调用的可能性。

    1. 唯一在编译时解决最终目标的方法调用是 private 方法和构造函数调用,以及从 Java 8 开始,static 方法调用在 interface 类型上。

      李>
    2. 对于非interface 类型的static 方法调用和super 方法调用,将在编译时设置一个目标类型,但JVM 可能会将该方法解析为超类型运行时指定的类型。尽管如此,解析的目标方法在特定的运行时永远不会改变,也不需要为每个方法调用解析,所以它是某种早期绑定,一旦方法被解析。但 JVM 通常会将解析推迟到调用指令的第一次实际执行。

    3. 对于其余的实例方法调用类型,目标方法是否在编译时声明final无关紧要。这些调用总是以相同的方式编码,如invokevirtual 指令,这意味着根据接收者对象类型查找实际的目标方法。您可以在编译调用者之后将方法更改为final 或非final,而不会破坏兼容性(除非您覆盖之后转换为final 的方法)。

      当接收器类型为interface 时,它在编译时永远不会被视为final,但在运行时仍会以final 方法结束。

      当然,在解析之后,JVM 可能会注意到目标方法已声明为final,并转向匹配上述第二种“早期绑定”的优化调用,另一方面,大多数 JVM 都足够智能对尚未声明 final 但实际上仍未被覆盖的方法执行相同操作(这可能适用于所有方法中的大多数)。因此,如果唯一的结果是优化也适用于其他方法,那么将 final 方法的调用称为“早期绑定”是没有意义的。

    【讨论】:

    • 更改了信息来源。我认为这些人使用了规范,这就是为什么我让我的问题更容易并引用了 java 规范,对此感到抱歉。我自己检查了文档,没有这样的声明,你是对的。是不是说明书和博文不对?
    • @Ivan Lymar:让我们说不精确或草率。他们忽略了类在编译后可能会发生变化的事实(实际上在库发展时会发生变化)。因此,他们的示例工作正常,因为他们假设编译和执行的环境相同,但不足以显示决定是在编译时还是运行时做出的,因为该决定的结果在两者中都是相同的案子。最后,这并不重要。 “后期绑定”的意思是,调用最终可能会根据实际的接收者类型以不同的实现方法结束,这与“早期绑定”相反……
    猜你喜欢
    • 1970-01-01
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多