2016-11-28 30 views
3

我对以下段落感到困惑(来源Oracle JVM specification for invokespecial instruction)。Oracle JVM:调用特殊指令

如果以下所有条件都为真,令C的 当前类的直接超类:

  1. 的解决方法是不是一个实例初始化方法(§2.9)。
  2. 如果符号引用命名一个类(不是接口),那么该类是当前类的超类。
  3. ACC_SUPER标志设置为类文件(§4.1)。在invokespecial指令描述第一段:

我提出了一些标签(// //标签符号)。我在下面的问题中使用了这个标签。

无符号indexbyte1和indexbyte2被用于构建一个索引 到当前类//当前类//(§2.6),其中该指数的 值的运行时间常数池(indexbyte1 < < 8)| indexbyte2。该索引处的运行时 恒定区项目必须是一个符号引用一个方法 或接口方法(§5.1),其给出的名称//方法名//和 描述符//方法描述符//(§4.3.3),以及对 类的参考符号//引用类//或其中将找到该方法的接口。名为 的方法已解决//解析方法//(第5.4.3.3节,第5.4.3.4节)。


基于标签我现在请与条件的段落。

  1. 的解决方法,没有一个实例初始化方法(§2.9)。

问题1:所以,我检查//方法名//不等于 “<初始化>” 或 “<clinit>”,对不对?

  • 如果符号参考名称的类(不是一个接口),则这个类是当前类的类的超类。
  • 问题2:这意味着什么?//引用类//必须是直接或非直接超类(超类的超类等)//当前类//

    1. ACC_SUPER标志设置为类文件(§4.1)。

    问题3:类类的文件? //引用类//

    回答

    2
    1. 的解决方法,没有一个实例初始化方法(§2.9)。

    所以,我检查//方法名//不等于 “<初始化>” 或 “<clinit>”,对不对?

    正确。那么,更确切地说,“不是实例初始化方法”只意味着方法名称不是<init>。但是因为调用方法<clinit>被禁止一般,所以推断方法名称既不是<init>也不是<clinit>是正确的。

  • 如果符号参考名称的类(不是一个接口),则这个类是当前类的类的超类。
  • 这是什么意思? //引用类//必须是直接或非直接超类(超类的超类等)//当前类//

    是的,如果被引用的类不是接口,它必须是当前类的超类。请注意,这是一个暗示在枚举之前陈述的“让C为当前类别的直接超类”的条件。有关更多,请参见下文。

    还值得注意的是,对于非接口目标类型,目标类型必须指示当前类或当前类的超类,如4.9.2. Structural Constraints中所定义。

  • 的ACC_SUPER标志被设置为类文件(§4.1)。
  • 哪个类的文件? //引用类//

    当前类的类文件,即包含invokespecial指令的类。请注意,这是一个事实上不存在的要求。继link to §4.1时,你会发现:

    ACC_SUPER标志表明这两种可供选择的语义是,如果它出现在这个类或者接口,由invokespecial指令(§invokespecial)表示。编译器到Java虚拟机的指令集应该设置ACC_SUPER标志。在Java SE 8及更高版本中,无论class文件中的标志的实际值和class文件的版本如何,Java虚拟机都会在每个class文件中考虑设置ACC_SUPER标志。

    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遇到这样的指令时,它将搜索超类型层次结构中最具体的方法,并考虑其中的任何覆盖。这可以确保在一个类中只有直接超类的依赖关系(除非在代码中有更多抽象类型的其他明确引用),并且允许重构,例如在类型层次结构中向上或向下移动方法,而不影响兼容性。

    枚举条件的字面含义是被引用的类可能是任何超类(标准编译器仅使用直接超类生成类文件)来实现直接超类将用于解析方法的条件任何状况之下。这包括在1.0.2之前执行为Java 1.0编译的类文件时的情况,现在忽略了ACC_SUPER的缺失。唯一支持非接口类型的其他情况是目标类型完全匹配当前类,它用于调用private方法。

    ACC_FLAG是为了向后兼容而推出的。它表示应该使用新的行为,但如上所述,最近的JVM只支持“新”行为,这是20年前的现状。