Some may find it similar to the SO question Will Java Final variables have default values? but that answer doesn't completely solve this, as that question doesn't directly print the value of x within instance initializer block.
The problem arises when I try to print x directly inside the instance initializer block, while having assigned a value to x before the end of the block :
class HelloWorld { final int x; { System.out.println(x); x = 7; System.out.println(x); } HelloWorld() { System.out.println("hi"); } public static void main(String[] args) { HelloWorld t = new HelloWorld(); } }
This gives a compile time error stating that variable x might not have been initialized.
$ javac HelloWorld.java HelloWorld.java:6: error: variable x might not have been initialized System.out.println(x); ^ 1 error
Instead of directly printing, I am calling a function to print:
class HelloWorld { final int x; { printX(); x = 7; printX(); } HelloWorld() { System.out.println("hi"); } void printX() { System.out.println(x); } public static void main(String[] args) { HelloWorld t = new HelloWorld(); } }
This compiles correctly and gives output
0 7 hi
What is the conceptual difference between the two cases?
There is no "result of undefined behaviour". The behaviour is undefined.
An uninitialized variable has an undefined value, often corresponding to the data that was already in the particular memory location that the variable is using. This can lead to errors that are very hard to detect since the variable's value is effectively random, different values cause different errors or none at all.
This gives a compile time error stating that variable x might not have been initialized.
There will be no default values or ability to run the code. It will be a compile time error and your code won't run. If the variables were class fields they would get default values for certain types or null otherwise.
In the JLS, §8.3.3. Forward References During Field Initialization, its stated that there's a compile-time error when:
Use of instance variables whose declarations appear textually after the use is sometimes restricted, even though these instance variables are in scope. Specifically, it is a compile-time error if all of the following are true:
The declaration of an instance variable in a class or interface C appears textually after a use of the instance variable;
The use is a simple name in either an instance variable initializer of C or an instance initializer of C;
The use is not on the left hand side of an assignment;
C is the innermost class or interface enclosing the use.
The following rules come with a few examples, of which the closest to yours is this one:
class Z { static int peek() { return j; } static int i = peek(); static int j = 1; } class Test { public static void main(String[] args) { System.out.println(Z.i); } }
Accesses [to static or instance variables] by methods are not checked in this way, so the code above produces output 0
, because the variable initializer for i
uses the class method peek()
to access the value of the variable j
before j
has been initialized by its variable initializer, at which point it still has its default value (§4.12.5 Initial Values of Variables).
So, to summarize, your second example compiles and executes fine, because the compiler does not check if the x
variable was already initialized when you invoke printX()
and when printX()
actually takes place at Runtime, the x
variable will be assigned with its default value (0
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With