为什么 Java 1.0.2 的接口成员没有设置 ACC_ABSTRACT?

Why interface Member from Java 1.0.2 does not have ACC_ABSTRACT set?

我写了一个简单的 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 的版本更正了这一点并将标志设置为 0x0601 (ACC_ABSTRACT | ACC_INTERFACE | ACC_PUBLIC)。

我能找到的最早的 JVM 规范(据称是 1.0.2)是这样说的(§4.1,第 86 页,已强调):

An interface is implicitly abstract (§2.13.1); its ACC_ABSTRACT flag must be set. An interface cannot be final; its implementation could never be completed (§2.13.1) if it were, so it could not have its ACC_FINAL flag set.

JVM 规范第 9 版 has similar words to say:

If the ACC_INTERFACE flag is set, the ACC_ABSTRACT flag must also be set, and the ACC_FINAL, ACC_SUPER, ACC_ENUM, and ACC_MODULE flags set must not be set.

Oracle/Sun JVM 是否强制执行 "must be" 的要求?如果有,从什么时候开始?如果不是,为什么 JVM 规范会假装它是必需的?

我不清楚 为什么 但我通过创建以下 类 进行了试验, 用 Java 9 的 javac 编译它们,然后在 Foo 中手动编辑 access_flags0x200;然后通过不同的 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.

中开始执行它

仍然不确定为什么。

这是一个错误 JDK-4059153:javac 没有为接口设置 ACC_ABSTRACT

该错误已在 1.2 中修复,但由于已经有许多 classes 编译了此错误,JVM 得到了一个解决方法,可以为所有 classes 自动添加 ACC_ABSTRACT ACC_INTERFACE。这一直有效到 Java 6,最终决定严格遵循更新的 class 文件的规范。但是,为了向后兼容旧版本的 class 文件,解决方法直到现在仍然存在,请参阅 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;
    }