First, a puzzle: What does the following code print?
public class RecursiveStatic {
public static void main(String[] args) {
System.out.println(scale
Class level members can be initialized in code within the class definition. The compiled bytecode cannot initialize the class members inline. (Instance members are handled similarly, but this is not relevant for the question provided.)
When one writes something like the following:
public class Demo1 {
private static final long DemoLong1 = 1000;
}
The bytecode generated would be similar to the following:
public class Demo2 {
private static final long DemoLong2;
static {
DemoLong2 = 1000;
}
}
The initialization code is placed within a static initializer which is run when the class loader first loads the class. With this knowledge, your original sample would be similar to the following:
public class RecursiveStatic {
private static final long X;
private static long scale(long value) {
return X * value;
}
static {
X = scale(10);
}
public static void main(String[] args) {
System.out.println(scale(5));
}
}
scale(10)
to assign the static final
field X
.scale(long)
function runs while the class is partially initialized reading the uninitialized value of X
which is the default of long or 0.0 * 10
is assigned to X
and the class loader completes.scale(5)
which multiplies 5 by the now initialized X
value of 0 returning 0.The static final field X
is only assigned once, preserving the guarantee held by the final
keyword. For the subsequent query of adding 3 in the assignment, step 5 above becomes the evaluation of 0 * 10 + 3
which is the value 3
and the main method will print the result of 3 * 5
which is the value 15
.