我对以下段落感到困惑(源Oracle JVM specification for invokespecial instruction)。 如果满足以下所有条件,则令C为的直接超类。 当前 class : 解决的方法不是实例初始化方法(第2.9节)。 如果符号引用命名一个类(不是接口),则该类是当前类的超类。 为类文件(第4.1节)设置了ACC_SUPER标志。 我在invokespecial指令说明的第一段中做了一些标签(符号: // label // )。我在以下问题中使用了此标签。 无符号的indexbyte1和indexbyte2用于构造索引 进入当前类的运行时常量池 //当前类// (第2.6节),其中 索引的值是(indexbyte1 该索引处的常量池项必须是对 方法或接口方法(第5.1节),其名称为 //方法名称// 和 说明符 //方法说明符// (第4.3.3节)以及对该方法的符号引用 类 //引用的类// 或要在其中找到方法的接口。命名 方法已解决 //已解决的方法// (第5.4.3.3节,第5.4.3.4节)。基于标签,我现在检查带有条件的段落。 解决的方法不是实例初始化方法(第2.9节)。 问题1 :那么,我检查 //方法名称// 是否等于“”或“”,对吗? 如果符号引用命名一个类(不是接口),则该类是当前类的超类。 问题2 :这是什么意思? //引用的类// 必须是的直接或非直接超类(超类的超类等)//当前类// ? 为类文件(第4.1节)设置了ACC_SUPER标志。 问题3 :哪个类的类文件? //引用的类// 吗? (adsbygoogle = window.adsbygoogle || []).push({}); 最佳答案 解决的方法不是实例初始化方法(第2.9节)。 因此,我检查 //方法名称// 是否不等于“”或“”,对吗?正确。好吧,更准确地说,“不是实例初始化方法”仅意味着该方法名称不是<init>。但是由于通常禁止调用名为<clinit>的方法,因此得出正确的结论是,方法名称必须既不是<init>也不是<clinit>,这是正确的。如果符号引用命名一个类(不是接口),则该类是当前类的超类。 这是什么意思? //引用的类// 必须是的直接或非直接超类(超类的超类等)//当前类// ?是的,如果引用的类不是接口,则它必须是当前类的超类。请注意,这是一个条件,它意味着在枚举之前声明“让C为当前类的直接超类”。有关更多信息,请参见下文。还值得注意的是,对于非接口目标类型,必须将目标类型表示为4.9.2. Structural Constraints中定义的当前类或当前类的超类。为类文件(第4.1节)设置了ACC_SUPER标志。 哪个 class 的 class 文件? //引用的类// 吗?当前类的类文件,即包含invokespecial指令的类。请注意,这实际上是不存在的要求。当您遵循link to §4.1时,您会注意到:ACC_SUPER标志指示如果出现在此类或接口中,则将由invokespecial指令(§invokespecial)表示两种替代语义中的哪一种。 Java虚拟机指令集的编译器应设置ACC_SUPER标志。在Java SE 8及更高版本中,Java虚拟机认为在每个ACC_SUPER文件中都设置了class标志,而不管class文件中标志的实际值和class文件的版本如何。存在ACC_SUPER标志是为了与旧的编译器为Java编程语言编译的代码向后兼容。在1.0.2之前的JDK版本中,编译器生成了access_flags,其中现在表示ACC_SUPER的标志没有分配的含义,如果设置了该标志,Oracle的Java虚拟机实现将忽略该标志。因此,当JVM“考虑在每个ACC_SUPER文件中设置class标志”时,无需检查必须设置标志的要求...历史方面也解释了上述含义。 invokespecial指令用于实现super.methodName(…)调用。在1.0的早期实现中,编译器解析了包含方法声明的目标类,并且JVM调用了该方法,而忽略了任何替代方法。这产生了两个问题。首先,恶意代码可以通过使用指向该方法超类型的适当invokespecial指令来绕过类型层次结构中的重写方法。此外,它创建了对超类层次结构的依赖关系,从而限制了可能的更改。当前的规则是,编译器将始终将super.methodName(…)编码为针对包含该调用的类的直接超类,而不管在编译时已在哪里找到了实际的声明。在运行时,当JVM遇到这样的invokespecial指令时,它将在超类型层次结构中搜索最具体的方法,并注意其中的任何覆盖。这样可以确保在一个类中,仅对其直接超类具有依赖性(除非在代码中存在对其他抽象类型的其他显式引用),并且它允许进行重构,例如在类型层次结构中上下移动方法,而不会影响兼容性。枚举条件的字面含义是,被引用的类可以是任何超类(标准编译器仅使用直接超类生成类文件)来满足在任何情况下都将使用直接超类来解析该方法的条件。这包括在执行为1.0.2之前的Java 1.0编译的类文件时的情况,因为现在忽略了ACC_SUPER的存在。非接口类型唯一支持的其他情况是目标类型与当前类完全匹配的情况,该类用于调用private方法。引入ACC_FLAG是为了向后兼容。它的存在表明应该使用新行为,但是如上所述,最近的JVM仅支持“新”行为,这是二十年来的最新水平。 (adsbygoogle = window.adsbygoogle || []).push({}); 09-12 04:45