Friday, December 16, 2011

Initialization block as a constructor for anonymous class

Although not broadly used, [static] initialization blocks are quite interesting features in Java. They may be used to initialize static and instance fields with own default values, before a constructor kicks in. In byte-code, such blocks are represented by two special methods: void <clinit>() for static initialization block and void <init>() for instance initialization block. There may be multiple declarations of initialization blocks in one class. In such case the code from each block is combined into one of the above methods. All instructions are invoked in the same order as they were declared in source code. Example:

package net.progsign.java6;

public class InitializationBlockTest {
 
 private static char charValue;
 private boolean boolValue;
 private int intValue;
 private String stringValue;
 
 static {
  charValue = '$';
  System.out.println("[clinit] " + charValue);
 }
 
 {
  System.out.println("[init-0] " + boolValue);
  System.out.println("[init-0] " + intValue);
  System.out.println("[init-0] " + stringValue);
  System.out.println();
 }
 
 {
  boolValue = true;
  intValue = 1024;
  stringValue = "default";
 }

 public InitializationBlockTest() {
  System.out.println("[constr] " + boolValue);
  System.out.println("[constr] " + intValue);
  System.out.println("[constr] " + stringValue);
 }
 
 public static final void main(String[] args) {
  new InitializationBlockTest();
 }
}

The output of the above code will be:
[clinit] $
[init-0] false
[init-0] 0
[init-0] null

[constr] true
[constr] 1024
[constr] default

Good code design expects from us to initialize class fields in a constructor. Also, because of the characteristics of initialization blocks, it may cause some confusion when trying to understand the order in which the object is created.
However, there is a case where initialization block may be successfuly used. Examine the following code:

package net.progsign.java6;

interface IFace {
 int method();
}

public class AnonymousConstructor {
 public static void main(String[] args) {
  // anonymous class implementing IFace interface
  IFace foo = new IFace() {
   private int value;
   
   {
    value = 1024;
    init();
   }
   
   public int method() {
    return value;
   }
   
   private void init() {
    System.out.println("<init> called init()");
   }
  };
  System.out.println("[main] foo.method() = " + foo.method());
 }
}

In the above code, I declared an interface IFace and, in the main() method, I created anonymous class that implements this interface. My anonymous class has one private attribute value of type int. Because anonymous classes have no name, thus it's not possible to define own constructor (default non-argument constructor will still be created for the class by the compiler). Without initialization blocks, we would be unable to init the class field with our own values.

When compiled and run, the code will produce the following output:

<init> called init()
[main] foo.method() = 1024

Things to know about [static] initialization blocks:
  • there may be multiple initialization blocks in one class (they run in the order they occur in code)
  • they are invoked before any constructor
  • you can't call constructors (neither super() nor this()) from inside initialization block
  • same as constructors, initialization blocks may throw runtime exceptions (in such case the object will not be created)
  • you can assign default value to fields declared as final, but only if they haven't been initialized at declaration time



PS: noticed quite an interesting behaviour of initialization blocks. See the following code:

package net.progsign.java6;

public class InitializationTest {

 static {
  sfield = 1;
  //System.out.println("<clinit> " + sfield);
  //System.out.println("<clinit> sfield=" + InitializationTest.sfield);
 }
 
 {
  ifield = 2;
  //System.out.println("<init> " + ifield);
  //System.out.println("<init>   ifield=" + this.ifield);
 }
 
 static int sfield = 10;
 int ifield = 20;
 
 public static void main(String[] args) {
  InitializationTest it = new InitializationTest();
  System.out.println("[main]   sfield=" + it.sfield);
  System.out.println("[main]   ifield=" + it.ifield);
 }
}

Will the code compile? What will be the output? What will happen if you uncomment the "System.out.println(...)" lines?