The following does not compile, giving an 'illegal forward reference' message:
class StaticInitialisation {
static
{
System.out.println("Test string is: " + testString);
}
private static String testString;
public static void main(String args[]) {
new StaticInitialisation();
}
}
However, the following does compile:
class InstanceInitialisation1 {
{
System.out.println("Test string is: " + this.testString);
}
private String testString;
public static void main(String args[]) {
new InstanceInitialisation1();
}
}
But the following does not compile, giving an 'illegal forward reference' message:
class InstanceInitialisation2 {
private String testString1;
{
testString1 = testString2;
}
private String testString2;
public static void main(String args[]) {
new InstanceInitialisation2();
}
}
Why do StaticInitialisation and InstanceInitialisation2 not compile, while InstanceInitialisation1 does?
Using an identifier before its declaration is called a forward reference, and results in an error, except in the following cases: When a goto statement refers to a statement label before the label's declaration. When a structure, union, or enumeration tag is used before it is declared. What is see reference? Answer: What is see reference?
Using an identifier before its declaration is called a forward reference, and results in an error, except in the following cases: When a goto statement refers to a statement label before the label's declaration. When a structure, union, or enumeration tag is used before it is declared.
Using an identifier beforeits declaration is called a forward reference, and results in an error, except in the following cases: When a gotostatement refers to a statement label before the label's declaration When a structure, union, or enumeration tag is used before it is declared
- Blurtit What Is Forward Referencing And Relocation Problem? Forward referencing is usually used in assembly language. In forward referencing variable or label is referenced before it is declared. Different problems can be solved using One Pass or Two Pass forward referencing.
This is covered by section 8.3.3 of the JLS:
Use of class variables whose declarations appear textually after the use is sometimes restricted, even though these class variables are in scope (§6.3). Specifically, it is a compile-time error if all of the following are true:
The declaration of a class variable in a class or interface C appears textually after a use of the class variable;
The use is a simple name in either a class variable initializer of C or a static 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.
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.
In your second case, the use isn't a simple name - you've got this
explicitly. That means it doesn't comply with the second bullet in the second list quoted above, so there's no error.
If you change it to:
System.out.println("Test string is: " + testString);
... then it won't compile.
Or in the opposite direction, you can change the code in the static initializer block to:
System.out.println("Test string is: " + StaticInitialisation.testString);
Odd, but that's the way it goes.
Lets look at these two example, I guess this will make you clear.
public class InstanceAndSataticInit {
{
System.out.println("Test string is (instance init): " + this.testString);
}
static{
System.out.println("Test string is (static init ): " + InstanceAndSataticInit.testStringStatic);
}
public static String testStringStatic="test";
public String testString="test";
public static void main(String args[]) {
new InstanceAndSataticInit();
}
}
Output:
Test string is (static init ): null
Test string is (instance init): null
And
public class InstanceAndSataticInitVariableFirst {
public static String testStringStatic="test";
public String testString="test";
{
System.out.println("Test string is (instance init): " + this.testString);
}
static{
System.out.println("Test string is (static init ): " + InstanceAndSataticInitVariableFirst.testStringStatic);
}
public static void main(String args[]) {
new InstanceAndSataticInitVariableFirst();
}
}
output :
Test string is (static init ): test
Test string is (instance init): test
So you can say the sequence are like this.
Static variable will be created but not be initialized.
Static initialization will be executed according to the given sequence.
By sequence I mean appearance in the code.
I guess this steps answer your two not working example StaticInitialisation
and InstanceInitialisation2
But in case your second working example InstanceInitialisation1
by using this
key word you are actually helping compiler to overlook the textual hierarchy. Same thing happen in case of static
when I call InstanceAndSataticInit.testStringStatic
in my first example InstanceAndSataticInit
Simple reason - it's too expensive or impossible to analyze and forbid all forward references. e.g.
{
print( getX(); ); // this.x
print( that().x ); // this.x
}
int x;
int getX(){ return x; }
This that(){ return this; }
The spec settles on forbidding some simple cases indicative of common programmer mistakes.
See also Recursive initializer works when I add "this"?
Here what we have to understand is that in 2nd code snippet You are using block and this keyword.
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