为什么Java 1.0.2的接口成员没有ACC_ABSTRACT集



我已经写了一个简单的Java字节码解析器来进行一些实验,最近它在一个意外的位置失败了。从Java 1.1.8.16的rt.jar读取java/lang/reflect/Member.java时,我的解析器很生气,因为Member像这样开始(请注意丢失的ACC_ABSTRACT标志):

Classfile Member.class
  Last modified Aug 8, 2002; size 350 bytes
  MD5 checksum 9a1aaec8e70e9a2ff9d63331cb0ea34e
  Compiled from "Member.java"
public interface java.lang.reflect.Member
  minor version: 3
  major version: 45
  flags: (0x0201) ACC_PUBLIC, ACC_INTERFACE
...

Java 1.2.2.17的版本对此进行了更正,并将标志设置为0x0601ACC_ABSTRACT | ACC_INTERFACE | ACC_PUBLIC)。

我可以找到的最早的JVM规范(据称是1.0.2)说这是这样说的(§4.1,第86页,添加了强调):

一个接口隐式抽象(§2.13.1);必须设置其ACC_ABSTRACT频率。接口不能是最终的;它的实施永远无法完成(第2.13.1节),因此无法拥有其ACC_FINAL频率集。

JVM规范的版本9具有类似的词:

如果设置了ACC_INTERFACE标志,则还必须设置ACC_ABSTRACT flag ,而ACC_FINALACC_SUPERACC_ENUMACC_MODULE和CC_14标志必须设置。

Oracle/Sun JVM是否强制执行"必须"的要求?如果是这样,什么时候?如果不是,为什么JVM规范会考虑需要假装?

这是一个错误JDK-4059153:Javac未为接口设置ACC_ABSTRACT

该错误是在1.2中固定的,但是由于已经有很多类带有此错误的类,因此JVM可以使用ACC_INTERFACE的所有类都可以自动添加ACC_ABSTRACT。直到Java 6终于决定严格遵循较新的类文件的规范时,这起作用了。但是,对于与类文件的较旧版本的向后兼容性,到目前为止,解决方法仍然存在,请参阅ClassFileParser.cpp:

    if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
      // Set abstract bit for old class files for backward compatibility
      flags |= JVM_ACC_ABSTRACT;
    }

我不清楚为什么用Java 9的javac编译它们,然后在Foo中手动编辑access_flags;然后通过不同的Java版本手动骑自行车minor_versionmajor_version,以查看会发生什么:

interface Foo { }
class Bar implements Foo {
    public static void main(String[] args) {
        System.out.println("BAZ");
    }
}

结果:

╭──────╥───────┬───────┬─────╮
│ Java ║ minor │ major │ out │
╞══════╬═══════╪═══════╪═════╡
│  1.1 ║    03 │    2d │ BAZ │
│  1.2 ║     " │     " │ BAZ │
│  1.3 ║     " │    2e │ BAZ │
│  1.4 ║    00 │    2f │ BAZ │
│   5  ║    00 │    31 │ BAZ │
│   6  ║    00 │    32 │ err │
│   7  ║    00 │    33 │ err │
│   8  ║    00 │    34 │ err │
│   9  ║    00 │    35 │ err │
└──────╨───────┴───────┴─────┘

其中" err"确实像这样打印出来:

Error: LinkageError occurred while loading main class Bar
    java.lang.ClassFormatError: Illegal class modifiers in class Foo: 0x200

所以我想他们终于在Java 6中实施了它。

仍然不确定为什么。

相关内容

  • 没有找到相关文章

最新更新