gpt4 book ai didi

java - 在接口(interface)中的静态方法上调用静态

转载 作者:搜寻专家 更新时间:2023-10-31 19:32:26 26 4
gpt4 key购买 nike

反汇编一些 Java 8 代码我发现一些 invokestatic 调用接口(interface)中的静态方法(特别是这是 java.util.function.Function.identity())在常量池中使用 InterfaceMethodRef;这是 javap -s -c -v p 给我看的:

    15: invokestatic  #66  // InterfaceMethod java/util/function/Function.identity:()Ljava/util/function/Function;

根据 JVM 8 spec这是不可能的,当我在 Java 7 版本(major version=51)的类文件中使用这条指令时,它在这条指令上抛出了 VerifyError。

但是,当我将主要版本更改为 52 时,它开始正常工作。请注意,我在 Oracle JDK 1.8.0_60 上运行。我想知道为什么需要进行此更改(调用的方法是静态链接的,不是吗?)以及是否在任何地方记录了这一点。

最佳答案

好吧,在 Java 8 之前,interface 中的 static 方法是不允许的,所以很明显,任何试图在以前的版本或类文件中使用它们的尝试都有旧版本注定要失败,无论它在 Java 8 中是如何实现的。

在 Java 8 之前,我们有以下两条规则:

  1. The class_index item of a CONSTANT_Methodref_info structure must be a class type, not an interface type.

    The class_index item of a CONSTANT_InterfaceMethodref_info structure must be an interface type.

    (参见 JVMSpec 7 §4.4.2)

  2. invokestatic 的方法描述符必须引用 CONSTANT_Methodref_info 条目

    (参见 JVMSpec 7 §6.5)

    The run-time constant pool item at that index must be a symbolic reference to a method (§5.1), which gives the name and descriptor (§4.3.3) of the method as well as a symbolic reference to the class in which the method is to be found.

    “对方法的符号引用”排除接口(interface)方法可能看起来不是那么清楚,但如果没有这个假设,我们对 Java 8 的行为就没有任何区别。通过与 Java 8 的 JVM 规范进行比较或考虑到接口(interface)方法始终暗示为非静态,它也会变得更加清晰。

很明显,为了在 interface 中添加对 static 方法的支持,通过 invokestatic 调用,至少有一个规则改变。

如果我们查看规则及其措辞,我们会发现第一个非常清楚,而在第二个中,“对方法的符号引用”指的是 CONSTANT_Methodref_info 条目并排除“对接口(interface)方法的符号引用”。我们决定更改该规则,同时使措辞更加清晰:

( JVMSpec 8 §6.5 ):

The run-time constant pool item at that index must be a symbolic reference to a method or an interface method (§5.1), which gives the name and descriptor (§4.3.3) of the method as well as a symbolic reference to the class or interface in which the method is to be found.

现在很明显 invokestatic 可以引用接口(interface)方法,因此不需要修改第一条规则,并且 it hasn’t been touched .但请注意,第一条规则从未强制接口(interface)方法为非static。它只与声明类型是否为 interface 有关。


这显然降低了 CONSTANT_Methodref_infoCONSTANT_InterfaceMethodref_info 之间的区别的值(value),但这是不可避免的。如果放宽第一条规则,它也会软化这种区别。

但是有一个强有力的理由改为更改调用方:由于引入了 default 方法,现在可以通过以下方式调用覆盖的 default 方法invokespecial 就像之前其他重写的非抽象方法一样。因此,invokespecial 现在也可以引用 interface 方法。

坚持调用指令的类型和常量池条目类型之间的匹配,就像旧规则一样,这意味着在 default 方法的情况下,我们有时需要两个池描述相同目标方法的条目,一个用于 invokeinterface,另一个用于 invokespecial

关于java - 在接口(interface)中的静态方法上调用静态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34360718/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com