The full description is in section 8.3.3 of the Java Language Specification: "Forward References During Field Initialization"
A forward reference (referring to a variable that is not declared yet at that point) is only an error if the following are all 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.
See the bolded text: "the use is a simple name". A simple name is a variable name without further qualification. In your code, b
is a simple name, but this.b
is not.
But why?
The reason is, as the cursive text in the example in the JLS states:
"The restrictions above are designed to catch, at compile time,
circular or otherwise malformed initializations. "
In other words, they allow this.b
because they think that a qualified reference makes it more likely that you have thought carefully about what you're doing, but simply using b
probably means that you made a mistake.
That's the rationale of the designers of the Java Language. Whether that is true in practice has, to my knowledge, never been researched.
Initialization order
To expand on the above, in reference to Dukeling's comment on the question, using a qualified reference this.b
will likely not give you the results you want.
I'm restricting this discussion to instance variables because the OP only referred to them.
The order in which the instance variables are assigned is described in JLS 12.5 Creation of New Class Instances.
You need to take into account that superclass constructors are invoked first, and that initializations code (assignments and initialization blocks) are executed in textual order.
So given
int a = this.b;
int b = 2;
you will end up with a
being zero (the value of b
at the time that a
's initializer was executed) and b
being 2.
Even weirder results can be achieved if the superclass constructor invokes a method that is overridden in the subclass and that method assigns a value to b
.
So, in general, it is a good idea to believe the compiler and either reorder your fields or to fix the underlying problem in case of circular initializations.
If you need to use this.b
to get around the compiler error, then you're probably writing code that will be very hard to maintain by the person after you.
a
's value will be0
(the default forint
), even if you setb
. So it doesn't give an error, but it also doesn't work. Surprisingly none of the answers mention this. – Onassis