Tuesday, 25 September 2007

Restrictions on the use of Fields during Initialization

Continuing Reading Java Language Specification turned to chapter Classes

Now in section Restrictions on the use of Fields during Initialization.

Can we predict the output of this program?

class Z {

int k=j;
static int i = j;
static int j = 4;

}

class ZZ extends Z {
static { i = j + 2; }
static int i, j;
static { j = 4; }
}

public class CircularInitializationsExample {

public static void main(String[] args) {
Z z=new Z();
Z zz=new ZZ();
System.out.println(z.i);
System.out.println(zz.i);
}
}

Well this results in compilation problem as there is circular initialization happening here.As static variables are initialized first hence i and j are in circular dependency which causes a compilation problem.
Also variable j is trying to be referenced before initialization.But this rule wont be applied for instance variables as instance variables are loaded after static variables being loaded.

For Example:
int k=j;
static int j=10;

These restrictions are designed to catch, at compile time, circular or otherwise
malformed initializations.

As JLS States:
The declaration of a member needs to appear textually before it is used only if the member is an instance (respectively static) field of a class or interface C and all of the following conditions hold:

The usage occurs in an instance (respectively static) variable initializer of C or in an instance (respectively static) initializer of C.
The usage is not on the left hand side of an assignment.
The usage is via a simple name.
C is the innermost class or interface enclosing the usage.
A compile-time error occurs if any of the four requirements above are not met.


An Eloborate Example as given in JLS where all the rules are followed.

class ElobarateExample {

static {
x = 100; // ok - assignment
int y = x + 1; // error - read before declaration
int v = x = 3; // ok - x at left hand side of assignment
int z = ElobarateExample.x * 2;
// ok - not accessed via simple name
Object o = new Object(){
void foo(){x++;} // ok - occurs in a different class
{x++;} // ok - occurs in a different class
};
}

{
j = 200; // ok - assignment
j = j + 1; // error - right hand side reads before declaration
int k = j = j + 1;
int n = j = 300; // ok - j at left hand side of assignment
int h = j++; // error - read before declaration
int l = this.j * 3; // ok - not accessed via simple name
Object o = new Object(){
void foo(){j++;} // ok - occurs in a different class
{ j = j + 1;} // ok - occurs in a different class
};
}

int w = x = 3; // ok - x at left hand side of assignment
int p = x; // ok - instance initializers may access static fields
static int u = (new Object(){int bar(){return x;}}).bar();
// ok - occurs in a different class
static int x;
int m = j = 4; // ok - j at left hand side of assignment
int o = (new Object(){int bar(){return j;}}).bar();
// ok - occurs in a different class
int j;
}

Hope this explanation helps.

No comments: