- 的解决方法,没有一个实例初始化方法(§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年前的现状。