Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do two programs have forward referencing errors while the third does not?

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?

like image 505
danger mouse Avatar asked Jun 15 '15 06:06

danger mouse


People also ask

What is a forward reference error?

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?

What is forward reference in C++?

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.

When is a gotostatement a forward reference?

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

What is forward referencing and relocation problem?

- 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.


4 Answers

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.

like image 62
Jon Skeet Avatar answered Oct 23 '22 02:10

Jon Skeet


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.

  1. Static variable will be created but not be initialized.

  2. Static initialization will be executed according to the given sequence.

  3. Non Static variable will be created but not be initialized.
  4. Non 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

like image 34
Saif Avatar answered Oct 23 '22 00:10

Saif


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"?

like image 2
ZhongYu Avatar answered Oct 23 '22 02:10

ZhongYu


Here what we have to understand is that in 2nd code snippet You are using block and this keyword.

  1. The block executes if object is created.
  2. That means the object is created in heap area.
  3. You are externally using this keyword to get a value of instance variable.
  4. Here object created with default values that will return as value.
  5. With out using this keyword you can't compile 2nd snippet also.
like image 1
Pulipati Prasadarao Avatar answered Oct 23 '22 02:10

Pulipati Prasadarao