As with so many of these questions, it's because the JLS says so.
8.3.2.3 Restrictions on the use of Fields during Initialization
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.
It is a compile-time error if any of the four requirements above are not met.
In your (failing) example, the "simple name" case is the condition not met. Qualifying the usage (with this
) is the loophole that resolves the compile-time error.
Explained another way:
The use of fields inside an initialization block before the line on which they are declared can only be on the left hand side of an expression (i.e. an assignment), unless they are qualified (in your case this.test
).
(paraphrased to suit this question more closely)