Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

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

Class and object initialization

Learn how to prepare classes and objects for use in an executing program

  • Print
  • Feedback

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.

Class initialization and class hierarchies

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.

  • Print
  • Feedback

Resources