invokestatic on interface中的静态方法 [英] invokestatic on static method in interface

查看:389
本文介绍了invokestatic on interface中的静态方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Disassembling some Java 8 code I found out that some invokestatic calls on static methods in interface (particularly this was java.util.function.Function.identity()) uses InterfaceMethodRef in const pool; this is what javap -s -c -v p show me:

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

根据 JVM 8规范这是不可能的,当我在classfile中使用这个指令时带有版本Java 7(主要版本= 51 ),它已在此指令上抛出VerifyError。

According to JVM 8 spec this is not possible, and when I've used this instruction in classfile with version Java 7 (major version=51), it has thrown VerifyError on this instruction.

然而,当我'我将主要版本更改为 52 ,它开始像魅力一样工作。请注意,我在Oracle JDK 1.8.0_60上运行。我想知道为什么需要这个改变(被调用的方法是静态链接的,不是吗?)以及是否记录在任何地方。

However, when I've changed the major version to 52, it started working like a charm. Note that I am running on Oracle JDK 1.8.0_60. I wonder why this change was needed (the invoked method is linked statically, isn't it?) and whether this is documented anywhere.

推荐答案

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

Well, before Java 8, static methods in interfaces were not allowed, so obviously, any attempt to use them in a previous version or within a class file having an older version is doomed to fail, regardless of how it is implemented in Java 8.

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

Before Java 8, we had the following two rules:



的class_index项目CONSTANT_Methodref_info 结构必须是类类型,而不是接口类型。

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

CONSTANT_InterfaceMethodref_info 结构必须是接口类型。

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

(参见 JVMSpec7§4.4.2

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

The method descriptor of an invokestatic must refer a CONSTANT_Methodref_info entry

(参见 JVMSpec7§6.5


该索引处的运行时常量池项必须是方法的符号引用( §5.1),它给出了方法的名称和描述符(§4.3.3),以及对要找到该方法的类的符号引用。

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.

可能看起来并不清楚对方法的符号引用会排除接口方法,但如果没有这种假设,我们根本不会对Java 8的行为产生任何影响。通过与Java 8的JVM规范进行比较,或者考虑到接口方法总是暗示为非 static ,它也会变得更加清晰。

It might not look that clear that "symbolic reference to a method" precludes interface methods, but without that assumption we had no difference to the behavior of Java 8 at all. It also will become clearer by comparing with the JVM specification for Java 8 or considering that interface methods were always implied to be non-static.

显然,在界面中添加对 static 方法的支持 s,要通过 invokestatic 调用,至少需要更改一条规则。

It should be obvious that for adding support for static methods in interfaces, to be invoked via invokestatic, at least one rule has to change.

如果我们看一下规则及其措辞,我们会看到第一个很清楚,而在第二个中,对方法的符号引用指的是 CONSTANT_Methodref_info 条目并排除对接口方法的符号引用。决定改变该规则并使措辞更清晰:

If we look at the rules and their wording, we see that the first one is quite clear whereas in the second one, it’s not entirely obvious that "symbolic reference to a method" is referring to CONSTANT_Methodref_info entries and precluding a "symbolic reference to an interface method". The decision was to change that rule and make the wording clearer at the same time:

JVMSpec8§6.5):


该索引处的运行时常量池项必须是对方法或接口方法(第5.1节)的符号引用,它提供了名称和描述符(第4.3.3节)该方法以及对要在其中找到该方法的类或接口的符号引用。

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 可以引用接口方法,因此不需要触及第一条规则,并且尚未触及。但请注意,第一条规则从未强制接口方法为非 static 。它只是关于声明类型是否是接口

Now it’s clear that invokestatic may refer to interface methods and thus the first rule doesn’t need to be touched, and it hasn’t been touched. But note that the first rule never mandated the interface methods to be non-static. It’s only about whether the declaring type is an interface or not.

这显然降低了 CONSTANT_Methodref_info CONSTANT_InterfaceMethodref_info 之间区别的价值,但这是不可避免的。如果放宽了第一条规则,它也会缓和这种区别。

This obviously reduces the value of the distinction between CONSTANT_Methodref_info and CONSTANT_InterfaceMethodref_info but this was unavoidable. If the first rule was relaxed instead, it would also soften this distinction.

但是有一个强有力的理由改变调用方面:由于引入了默认方法,现在可以通过 invokespecial 默认方法$ c>就像之前的其他重写的非 abstract 方法一样。因此, invokespecial 现在也可以引用 interface 方法。

But there was a strong reason to change the invocation side instead: due to the introduction of default methods, there is now the possibility to invoke an overridden default method via invokespecial just like other overridden non-abstract methods before. Thus, invokespecial may now refer to interface methods as well.

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

Insisting on a match between the type of the invocation instruction and the constant pool entry type, like with the old rules, would imply that in the case of default methods, we would sometimes need two pool entries to describe the same target method, one for invokeinterface and a different one for invokespecial.

这篇关于invokestatic on interface中的静态方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆