Java类文件的ACC_SUPER访问标志的目的是什么? [英] What is the purpose of the ACC_SUPER access flag on Java Class files?

查看:1909
本文介绍了Java类文件的ACC_SUPER访问标志的目的是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

调用特殊 JVM指令用于在创建新对象时调用初始化方法(< init> )。指令的描述暗示(但不能说明)是否调用超类的构造函数或当前类的构造函数的决定取决于 ACC_SUPER

The invokespecial JVM instruction is used for calling initialisation methods (<init>) when creating new objects. The description of the instruction suggests (but doesn't clarify) that the decision on whether to call the constructor of a superclass or a constructor of the current class depends on the state of the ACC_SUPER flag set within the class file.

从Sun JVM规范:

From the Sun JVM Specification:


接下来,除非满足以下所有条件,否则选择调用的方法:

Next, the resolved method is selected for invocation unless all of the following conditions are true:


  • 为当前类设置了ACC_SUPER标志(见表4.1类访问和属性修饰符)。

- 来源调用特殊操作码定义)

-- Source (invokespecial opcode definition)


ACC_SUPER标志的设置指示两Java虚拟机要表达的调用特定指令的替代语义;存在ACC_SUPER标志以用于由Sun的旧编译器针对Java编程语言编译的代码的向后兼容性。 Java虚拟机的所有新实现都应该实现本规范中记录的invokespecial的语义。对于Java虚拟机的指令集的所有新编译器都应设置ACC_SUPER标志。 Sun的旧编译器生成了未设置ACC_SUPER的ClassFile标志。 Sun的较早的Java虚拟机实现会忽略该标志(如果已设置)。

The setting of the ACC_SUPER flag indicates which of two alternative semantics for its invokespecial instruction the Java virtual machine is to express; the ACC_SUPER flag exists for backward compatibility for code compiled by Sun's older compilers for the Java programming language. All new implementations of the Java virtual machine should implement the semantics for invokespecial documented in this specification. All new compilers to the instruction set of the Java virtual machine should set the ACC_SUPER flag. Sun's older compilers generated ClassFile flags with ACC_SUPER unset. Sun's older Java virtual machine implementations ignore the flag if it is set.

- 来源 ClassFile 格式)

定义表示该标志用于与旧编译器向后兼容。但是,它违背了 Sun的较早的Java虚拟机实现忽略标志,如果它被设置。

The definition states that the flag is for backward compatibility with old compilers. However it goes on to contradict with Sun's older Java virtual machine implementations ignore the flag if it is set.

该标志仍然使用 invokespecial 操作码?从我可以告诉,它似乎没有目的,我找不到一个资源,建议它曾经做过。

Is the flag still used with the invokespecial opcode? From what I can tell, it seems to hold no purpose and I can't find a resource to suggest it ever did.

谢谢。

推荐答案

引入了ACC_SUPER来纠正超级方法的调用问题。 ACC_SUPER标志将针对操作码183指令的改变的语义而编译的类标记。它的目的类似于类文件版本号,因为它允许JVM检测一个类是否为该指令的较旧或较新的语义编译。 Java 1.0.2没有设置和忽略ACC_SUPER,而Java 1.1和更高版本总是设置ACC_SUPER。

ACC_SUPER was introduced to correct a problem with the invocation of super methods. The ACC_SUPER flag marks a class as compiled for the changed semantics of the opcode 183 instruction. It's purpose is similar to that of the class file version number as it allows the JVM to detect whether a class was compiled for the older or newer semantics of that instruction. Java 1.0.2 did not set and ignored ACC_SUPER while Java 1.1 and later always sets ACC_SUPER.

在Java 1.1之前,使用操作码183的字节码指令, c $ c> invokespecial 被称为 invokenonvirtual ,并且具有部分不同的规范。每当实例方法必须被调用而没有虚拟方法查找时,它被使用。这是私人方法,实例初始化器(构造函数)的情况,并在 super 上实现方法调用。

Before Java 1.1 the byte code instruction with opcode 183 that is now called invokespecial was called invokenonvirtual and had a partially different specification. It was used whenever instance methods had to be invoked without a virtual method lookup. This was the case for private methods, instance initializers (constructors) and to implement method invocations on super. But the latter case caused problems with evolving class libraries.

以字节代码( CONSTANT_Methodref_info )的方法引用不仅仅是定义方法的名称,参数和返回类型,但也定义它所属的类。操作码183获得这样的方法引用参数,并且意图从指定的类直接调用引用的方法而不进一步查找。在 super 上的调用的情况下,编译器负责解析实现此方法的最近的超类并生成对它的字节代码的引用。

A method reference in byte code (CONSTANT_Methodref_info) not only defines the name and the argument and return types of a method but also the class to which it belongs. Opcode 183 gets such a method reference parameter and was meant to directly invoke the referenced method from the specified class without further lookups. In the case of invocations on super it was the compilers responsibility to resolve the closest super class that implements this method and generate a reference to it into the byte code.

从Java 1.1开始,它被改为基本上忽略在 CONSTANT_Methodref_info 中引用的类,并且改为对最近的超级方法进行查找在JVM中给定的方法名和签名。这通常在类被加载时或者在第一次执行指令或JIT编译之前完成。

Since Java 1.1 it was changed to essentially ignore the class referenced in CONSTANT_Methodref_info and to instead do the lookup for the closest super method with the given method name and signature in the JVM. This is usually done now when the class gets loaded or right before the instruction is executed or JIT compiled the first time.

下面是一个示例,说明为什么这个更改是必需的。在Java 1.0.2中,AWT类Container和Component通过这种方式定义:

Here is an example why this change was neccessary. In Java 1.0.2 the AWT classes Container and Component were defined this way:

class Component
{
    public void paint( Graphics g ) {}
}

class Container extends Component
{
    // inherits paint from Component but doesn't override it
}

在Java 1.1中,Conatiner类更改为自己实现 paint

In Java 1.1 the class Conatiner was changed to have it's own implementation of paint:

class Container extends Component
{
    public void paint( Graphics g ) {/*...*/}
}

你有一个直接或间接的Container子类,在 super.paint(g)上调用并编译它为1.0.2它生成一个 invokenonvirtual Component.paint 指令,因为这是拥有此方法的第一个父级。但是如果你在一个也有 Container.paint 的JVM上使用这个编译类,它仍然会调用 Component.paint 这不是你期望的。

Now when you had a direct or indirect subclass of Container that made a call on super.paint(g) and compiled it for 1.0.2 it generated a invokenonvirtual instruction for Component.paint since this was the first parent that had this method. But if you used this compiled class on a JVM that also had Container.paint it would still have called Component.paint which is not what you would expect.

另一方面,当你编译1.1的类并在1.0.2 JVM上执行它会抛出一个AbstractMethodError或更可能是那个时代的虚拟机只是崩溃。为了避免崩溃,你必须编写((Component)super).paint(g)并使用1.1编译器编译它,以获得所需的行为。这将设置ACC_SUPER,但仍然生成调用 Component.paint 的指令。一个1.0.2虚拟机将忽略ACC_SUPER并直接调用 Component.paint 这是罚款,而1.1 VM将找到ACC_SUPER设置,从而做查找本身,这将使它即使字节代码方法引用 Component.paint ,也会调用 Container.paint

On the other hand, when you compiled the class for 1.1 and executed it on a 1.0.2 JVM it would throw a AbstractMethodError or more likely for VMs of that era simply crash. To avoid the crash you had to write ((Component)super).paint(g) and compile it with a 1.1 compiler to get the desired behaviour in either VM. This would set ACC_SUPER but still generate the instruction to call Component.paint. A 1.0.2 VM would ignore ACC_SUPER and go straight to invoke Component.paint which is fine while a 1.1 VM would find ACC_SUPER set and thus do the lookup itself which would make it invoke Container.paint even though the byte code method reference was Component.paint.

有关详情,请访问此旧帖子the ikvm.net weblog

这篇关于Java类文件的ACC_SUPER访问标志的目的是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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