javainner-classesbytecode

How is the INNERCLASS field in java classes used?


I looked at some java bytecode using ASM, and was very surprised when I saw these lines

public class C1 {

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

  //..
}

C1 has an INNERCLASS declaration for a class contained in C2. Is this how it's supposed to be? If so, why is it needed, and doesn't it lead to much redundancy?

I compiled a minimal example that has a local variable of the inner type in the main method of the outer type using Eclipse Indigo SR1, for what it's worth. Should I report a bug?


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 {}
}

Solution

  • From the Java Virtual Machine Specification:

    If the constant pool of a class or interface C contains at least one CONSTANT_Class_info entry (§4.4.1) which represents a class or interface that is not a member of a package, then there must be exactly one InnerClasses attribute in the attributes table of the ClassFile structure for C.

    That is, the InnerClasses attribute references all inner classes ("class or interface not a member of a package") referenced in the class file, even if they aren't members of the class contained in the class file. One other case (which might be called outer classes for lack of a specific term) is explicitly called out in a note:

    In addition, the constant_pool table of every nested class and nested interface must refer to its enclosing class, so altogether, every nested class and nested interface will have InnerClasses information for each enclosing class and for each of its own nested classes and interfaces.

    As for why these external references are needed, I'm not entirely certain, except to note that inner classes were added in Java 1.1 after the class file format was mostly frozen, so information about inner classes isn't stored directly in the ClassFile structure (the top-level structure of a class file) like the superclass, interfaces, fields and methods are. Also note that the InnerClasses attribute is 8 bytes plus 8 bytes for each inner class referenced -- that's hardly a prohibitive amount of redundancy.