0

我查看了一些使用 ASM 的 java 字节码,当我看到这些行时非常惊讶

public class C1 {

  // compiled from: C1.java
  // access flags 0x9
  public static INNERCLASS C2$C3 C2 C3

  //..
}

C1有一个INNERCLASS包含在 中的类的声明C2。这是应该的吗?如果是这样,为什么需要它,而且它不会导致很多冗余吗?

我使用 Eclipse Indigo SR1 编译了一个最小示例,该示例在外部类型的主要方法中具有内部类型的局部变量,这是值得的。我应该报告错误吗?


public class C1 {
    public static void main(String[] args) throws Exception {
        C2.C3 c3 = new C2.C3();

        ClassReader cr = new ClassReader(C1.class.getName());
        cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), 0);
    }
}

public class C2 {
    public static class C3 {}
}
4

1 回答 1

1

来自Java 虚拟机规范

如果类或接口 C 的常量池包含至少一个 CONSTANT_Class_info 条目(第 4.4.1 节),它表示不是包成员的类或接口,则在属性表中必须恰好有一个 InnerClasses 属性C 的 ClassFile 结构。

也就是说,该属性引用InnerClasses了类文件中引用的所有内部类(“类或接口不是包的成员”),即使它们不是类文件中包含的类的成员。另一种情况(由于缺少特定术语可能被称为外部类)在注释中明确指出:

此外,每个嵌套类和嵌套接口的常量池表都必须引用其封闭类,因此总的来说,每个嵌套类和嵌套接口都将具有每个封闭类及其每个嵌套类和接口的 InnerClasses 信息。

至于为什么需要这些外部引用,我并不完全确定,只是需要注意的是,Java 1.1 中添加了内部类,是在类文件格式大部分被冻结之后,因此有关内部类的信息不直接存储在ClassFile结构中(类文件的顶层结构),如超类、接口、字段和方法。另请注意,该InnerClasses属性是 8 个字节加上每个引用的内部类的 8 个字节——这几乎不是一个令人望而却步的冗余量。

于 2014-05-22T10:21:51.463 回答