If you are getting Class object a class using Foo.class construct ("class literals"), the class Foo is not initialized - i.e., the static initializer of the class will not called at that point.
class Main {
public static void main(String[] args) {
System.out.println(Foo.class);
}
}
class Foo {
static {
System.out.println("Initializing Foo..");
}
}
When we compile and run the above Main class with JDK 1.5, we get the following output (I got this on my PC)
D:\>java -cp . Main
class Foo
We don't see "Initializing Foo.." in the output! -- because Foo.class does not initialize the class Foo. But, if we compile the classes with the command
D:\>javac -source 1.4 -target 1.4 Main.java
Now, if we run the class,
D:\>java -cp . Main
Initializing Foo..
class Foo
This time class Foo is initialized! And we get the same result with JDK 1.4.2 - i.e., if you JDK 1.4.2's javac, we see that classFoo is initialized. What is happening...??
Before 1.5, javac compiled Foo.class construct by using Class.forName(String) method:
D:\>javap -c Main
Compiled from "Main.java"
class Main extends java.lang.Object{
static java.lang.Class class$Foo;
Main();
Code:
0: aload_0
1: invokespecial #6; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #7; //Field java/lang/System.out:Ljava/io/PrintStream;
3: getstatic #8; //Field class$Foo:Ljava/lang/Class;
6: ifnonnull 21
9: ldc #9; //String Foo
11: invokestatic #10; //Method class$:(Ljava/lang/String;)Ljava/lang/Class;
14: dup
15: putstatic #8; //Field class$Foo:Ljava/lang/Class;
18: goto 24
21: getstatic #8; //Field class$Foo:Ljava/lang/Class;
24: invokevirtual #11; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
27: return
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
}
Starting from 1.5, javac uses ldc_w instruction to compile Foo.class
D:\>javap -c Main
Compiled from "Main.java"
class Main extends java.lang.Object{
Main();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc_w #3; //class Foo
6: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/Obj
ect;)V
9: return
}
The ldc_w instruction for class literals does not initialize the class. Is the behaviour of 1.5 wrong? i.e., violation of Java Language Spec? No! The language specification for initialization has not changed. It never listed class literal evaluation as an initialization trigger. Class.forName(String) method does initialize the class and therefore translating Foo.class with with Class.forName(String) resulted in the (unwanted) initialiazation of Foo. If you want the old behaviour you may want to use the workaround
documented in 5.0 Compatibility notes.