javaclassjvmbytecode

Can a Java inner class have static initialization in bytecode?


This is NOT the same question as: Why can't an inner class use static initializer? or other similar ones, since it's unrelated to the Java language semantics and relates purely to bytecode and the class file format/JVM behaviour.

I'm doing some bytecode rewriting which involves adding synthetic static fields to classes. I was wondering if the JVM/bytecode spec allows me to add static fields and a <clinit> method to an inner class or not? So far nothing has complained, but I don't want to rely on something which I can't point to a bit of the spec for.

If not, it's frustrating since I'd have to walk up to the nearest non-inner class parent and add the fields there (except I'm transforming one class file at a time, so this becomes awkward).


Solution

  • When inner classes were introduced in Java 1.1, no change to the bytecode format was made. In other words, inner classes are just classes like top level classes, except for a special attribute describing the relationship, which is used by compilers and by Reflection, but ignored by the JVM. Note that the linked section of the specification even says explicitly:

    Oracle's Java Virtual Machine implementation does not check the consistency of an InnerClasses attribute against a class file representing a class or interface referenced by the attribute.

    So, not only does the attribute have no effect on the actual execution, the JVM will not even check the plausibility of the contained information.

    The ability of nested classes to access each others private members has been syntactic sugar until Java 11, implemented by the compiler by inserting synthetic helper methods. Java 11 introduced new attributes to allow true access without such helper methods, however, this feature is distinct from Java source code level inner classes.

    So in short, since there are no special rules for inner classes on the bytecode level, a <clinit> method is allowed for inner classes.