|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 2 of 3
>java Main
load attempt #0:
java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:140)
at Main.main(Main.java:17)
Caused by: java.lang.RuntimeException: failing static initializer...
at Main$X.<clinit>(Main.java:40)
... 3 more
load attempt #1:
java.lang.NoClassDefFoundError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:140)
at Main.main(Main.java:17)
load attempt #2:
java.lang.NoClassDefFoundError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:140)
at Main.main(Main.java:17)
It is slightly surprising that the errors on subsequent load attempts are instances of java.lang.NoClassDefFoundError. What happens here is that the JVM has already noted the fact that X has been loaded (before the initialization is attempted), and the class cannot be unloaded until the current classloader
is garbage collected. So, on subsequent calls to Class.forName(), the JVM does not attempt initialization again but, rather misleadingly, throws an instance of NoClassDefFoundError.
The proper way to reload such a class is to discard the original classloader instance and create a new one. Of course, this
can be done only if you had anticipated that and used the proper three-parameter form of forName().
I am sure you have used Java's X.class syntax to obtain a Class object for a class whose name is known at compile time. Less well known is how this is implemented at the byte-code level.
The details are different across compilers, but all of them generate code that uses the one-parameter form of Class.forName() behind the scenes. For example, javac from J2SE 1.4.1 translates Class cls = X.class; into the following equivalent form:
...
// This is how "Class cls = X.class" is transformed:
if (class$Main$X == null)
{
class$Main$X = class$ ("Main$X");
}
Class cls = class$Main$X;
...
static Class class$ (String s)
{
try
{
return Class.forName (s);
}
catch (ClassNotFoundException e)
{
throw new NoClassDefFoundError (e.getMessage());
}
}
static Class class$Main$X; // A synthetic field created by the compiler
Of course, everything mentioned above about Class.forName()'s short form always initializing the class in question applies to X.class syntactic form as well. The details are different when such syntax is used to get Class objects for primitive and array types, and I leave that as an exercise for curious readers.
In the previous example, you saw that the result of loading the class was cached in a special package-private static field
artificially created by the compiler, and a synthetic helper method executed Class.forName(). The reason this is convoluted may be because the syntax used was unavailable in early Java versions, so the feature was
added on top of the Java 1.0 byte-code instruction set.
Armed with this insight, you can have a bit of fun at the compiler's expense. Compile this tongue-in-cheek code snippet using javac from J2SE 1.3.1: