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

4

我写了一个简单的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页,重点强调):
接口隐式地是抽象的(§2.13.1);必须设置其ACC_ABSTRACT标志。接口不能是final;如果是,则其实现永远无法完成(§2.13.1),因此不能设置其ACC_FINAL标志。
JVM规范的第9版也有类似的说法
如果设置了ACC_INTERFACE标志,则必须同时设置ACC_ABSTRACT标志,并且不得设置ACC_FINALACC_SUPERACC_ENUMACC_MODULE标志。
Oracle/Sun JVM是否执行此“必须”要求?如果是,从何时开始?如果不是,为什么JVM规范会假装它是必需的?
2个回答

5

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

该bug在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;
    }

谢谢@apangin。解决我的问题并提供两个源材料链接,真的非常感激! - 0xbe5077ed

0

我不清楚为什么,但我尝试创建了以下类,使用Java 9的javac编译它们,然后手动编辑access_flags以在Foo中设置0x200;然后手动循环minor_versionmajor_version通过不同的Java版本来查看会发生什么:

interface Foo { }

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

结果:

╭──────╥───────┬───────┬─────╮
│ Java ║ minor │ major │ out │
╞══════╬═══════╪═══════╪═════╡
│  1.1032d │ 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中开始执行它了。

仍然不确定为什么。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接