|
|
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 6 of 9
Listing 7. ClassInitializationDemo5.java
// ClassInitializationDemo5.java
import java.io.*;
class ClassInitializationDemo5
{
final static double PI;
static
{
PI = 3.14159;
int i;
for (i = 0; i < 5; i++)
System.out.println (i);
}
static int j = i;
public static void main (String [] args)
{
System.out.println ("PI = " + PI);
}
}
When you compile ClassInitializationDemo5, the compiler reports an error when it encounters static int j = i; because it cannot find i -- i is local to the class block initializer. However, if you comment out static int j = i; and recompile, you don't receive a compiler error. Instead, you receive the following output:
0 1 2 3 4 PI = 3.14159
You might think it bizarre to see the declaration of constant PI without a class field initializer to initialize that constant. However, as long as PI explicitly initializes to 3.14159 in either a class field initializer or in a class block initializer, the compiler does not complain.
Thus far, you have only seen class field initializers and class block initializers in the context of a single class. How does
class initialization work in the context of a class hierarchy? When a class hierarchy is involved, the compiler creates a
separate <clinit> method for each class in that hierarchy. At runtime, the JVM loads all hierarchy classes and calls their <clinit> methods in a top-to-bottom order. That means the highest superclass's <clinit> method (which is Object's <clinit> method) executes first. After Object's <clinit> method completes, the next highest superclass's <clinit> method executes. The process continues in a top-down fashion until the class with the main() method's <clinit> method (if present) executes. Listing 8 demonstrates the <clinit> execution order:
Listing 8. ClassInitializationDemo6.java
// ClassInitializationDemo6.java
class Parent
{
static int a = 1;
static
{
System.out.println ("a = " + a);
System.out.println ("Parent initializer");
}
}
class ClassInitializationDemo6 extends Parent
{
static int b = 2 + a;
static
{
System.out.println ("b = " + b);
System.out.println ("Child initializer");
System.out.println ("a = " + a);
}
public static void main (String [] args)
{
}
}
ClassInitializationDemo6 introduces a pair of classes: Parent and ClassInitializationDemo6. Each class's <clinit> method executes the byte code instructions comprising that class's class field initializer and class block initializer. To
prove to yourself that Parent's <clinit> method executes before ClassInitializationDemo6's <clinit> method, examine the following ClassInitializationDemo6 output:
a = 1 Parent initializer b = 3 Child initializer a = 1
The output shows that Parent's class field initializer = 1; executes first. Next, Parent's class block initializer executes. Moving on, ClassInitializationDemo6's class field initializer = 2 + a; executes. Finally, ClassInitializationDemo6's class block initializer executes. And that is pretty much all there is to know regarding class initialization and class
hierarchies.