Did you know that it’s possible to reference a Java class without initialising it? I do. But I didn’t know it when I got into the office this morning.
There are several steps the JVM must go through before a program can use a class. These steps are detailed in section 12 of the Java Language Specification. In summary, before a class can be used it must be loaded, linked, and then initialised. I’d always been aware of these three steps, but I thought that the JVM would attempt all three steps as soon as the class was referred to.
It turns out that this is not the case. Section 12.4.1 lists the specific circumstances in which initialisation occurs. It is more than possible to have a class that is loaded and linked but not yet initialised, leaving several ways in which one can refer to an uninitialised class. For instance – and I’ve spent a good five or six hours tracking this one down – executing a statement such as ”
Class c = MyClass.class;” won’t initialise
Be wary of this behaviour when dynamically loading classes that are expected to register themselves with some registry, or create
static final instances of themselves. My code uses commons-lang enums. Subclasses of Enum have static final instances which register themselves with the base class. The code also has a Hibernate UserType which converts the enum instances to and from strings, in a manner similar to this recipe. Everything works fine, unless the application tries to read from the database without having first executed particular – and seemingingly unrelated – pieces of functionality which just happen to cause the JVM to initialise the subclass.
For my code, the solution was to put an empty static method, named
forceInit(), on each of the Enum subclasses. I then arranged for
forceInit() to be called at the appropriate time from within the Hibernate User Type. Simple when you know what the problem is.
Finally, I’d just like to note that
Class.forName(“mypackage.MyClass”) initialises MyClass after it loads it, while the other
Class.forName() variant has a parameter to control whether or not the newly loaded class should be initialised. None of the Classloader methods initialise a class.