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

时间:2017-12-18 14:54:09

标签: java jvm bytecode .class-file jvm-bytecode

我编写了一个简单的Java字节码解析器来进行一些实验,最近它在一个意想不到的地方失败了。从Java 1.1.8.16的['training', 'working', 'carrying'] 中读取java/lang/reflect/Member.java时,我的解析器生气,因为rt.jar就像这样开始(注意缺少Member标志):

ACC_ABSTRACT

Java 1.2.2.17中的版本对此进行了更正,并将标记设置为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 ... 0x0601)。

我能找到的最早的JVM规范(据称是1.0.2)就是这样说的(§4.1,p.86,强调增加):

  

接口是隐式抽象的(§2.13.1);必须设置ACC_ABSTRACT | ACC_INTERFACE | ACC_PUBLIC fl ag 。界面不能是最终的;如果它的实现永远不会完成(§2.13.1),那么它就不能设置ACC_ABSTRACT fl。

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

  

如果设置了ACC_FINAL标记,则还必须设置ACC_INTERFACE标记 ACC_ABSTRACTACC_FINAL,{{1不得设置{}和ACC_SUPER标志。

Oracle / Sun JVM是否强制执行“必须”这样的要求?如果是这样,那么什么时候如果没有,为什么JVM规范会假装它是必需的?

2 个答案:

答案 0 :(得分:4)

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

该错误已在1.2中修复,但由于已经编译了许多使用此错误的类,因此JVM得到了一种解决方法,可以为ACC_ABSTRACT的所有类自动添加ACC_INTERFACE。直到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;
    }

答案 1 :(得分:0)

我不清楚为什么但是我通过创建以下类来进行实验, 使用Java 9 -silent编译它们,然后在javac中手动编辑access_flags0x200;然后通过不同的Java版本手动循环Foominor_version以查看会发生什么:

major_version

结果:

interface Foo { }

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

哪里&#34;错误&#34;真打印出这样的:

╭──────╥───────┬───────┬─────╮
│ 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 │
└──────╨───────┴───────┴─────┘

所以我猜他们终于开始在Java 6中强制执行它了。

仍然不确定原因。