I've been doing some personal research in Java bytecode and I came across a bit of an oddity. If I decompile this class, I find a reference to Class.forName()
hanging out in the constant pool. However, there is no reference in the source code to this method.
I assume that something about this code is causing javac to emit a bit of code that dynamically loads a class, but I'm not sure why this happens. It strikes me as inefficient, but mainly I'm just curious as to why this happens.
After disassembling the code with javap
, I noticed that there is a method that doesn't exist in the source code:
static java.lang.Class class$(java.lang.String);
Code:
0: aload_0
1: invokestatic #1 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
4: areturn
5: astore_1
6: new #3 // class java/lang/NoClassDefFoundError
9: dup
10: invokespecial #4 // Method java/lang/NoClassDefFoundError."<init>":()V
13: aload_1
14: invokevirtual #5 // Method java/lang/NoClassDefFoundError.initCause:(Ljava/lang/Throwable;)Ljava/lang/Throwable;
17: athrow
Exception table:
from to target type
0 4 5 Class java/lang/ClassNotFoundException
It looks like this is generated in bytecode compiled for version < JDK1.5 whenever there is a class literal referenced in the code [1]. Basically, this:
if (getClass() == Level.class) {}
turns into this:
if (getClass() == class$("org.apache.log4j.Level")) {}
and class$()
looks like this:
static Class class$(java.lang.String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new NoClassDefFoundError();
}
}
Apparently in JDK1.5, the ldc_w
instruction was given the ability to load class constants and the class$()
method was no longer necessary.