Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with illegal forward reference in Java [duplicate]

Tags:

java

Why when I use reference this in a variable declaration, illegal forward reference doesn't appear? What's the difference between declaration with this and without it?

The following example fails to compile because of the illegal forward reference:

class FailsToCompile {
    int a = b; //illegal forward reference
    int b = 10;
}

By qualifying the use of b by this the compilation error goes away.

class Compiles {
    int a = this.b; //that's ok
    int b = 10;
}
like image 488
Dmitry Avatar asked May 02 '19 09:05

Dmitry


People also ask

What is illegal forward reference in Java?

"Illegal forward reference" means that you are trying to use a variable before it is defined. The behavior you observe is a symptom of a javac bug(see this bug report). The problem appears to be fixed in newer versions of the compiler, e.g. OpenJDK 7.

Are forward references allowed in Java?

Java allows very flexible forward references. A method may refer to a variable or another method of its class, regardless of where in the current class the variable or method is defined.


1 Answers

Assuming the following class

public class MyClass {
    int a = b;
    int b = 10;
}

The JLS 8.3.3. states in your case :

Use of instance variables whose declarations appear textually after the use is sometimes restricted
- The use is a simple name in either an instance variable initializer of C or an instance initializer of C

Now, using the member this allows you to access an instance that is already declared with default values ( a = 0, b = 0 ) but not yet fully initialized. This is visible if you check the result of:

public class MyClass {
    int a = this.b;
    int b = 10;
}

You would not get the expected value :

new MyClass().a //0
new MyClass().b //10

I can't explain why this is legal exactly since this would never give a correct value. We can find some explanation about why the restriction exist :

The restrictions above are designed to catch, at compile time, circular or otherwise malformed initializations.

But why allowing this to works...


Knowing that during an initialization of an instance, the following actions occurs :

  1. Member declaration
  2. Block execution and Field initialization in order
  3. Constructor execution

Give some strange behavior:

public class MyClass {

    {
        b = 10;
    }
    int a = this.b;
    int b = 5;
    {
        b = 15;
    }

    public static void main(String[] args) {
        MyClass m = new MyClass();
        System.out.println(m.a); //10
        System.out.println(m.b); //15
    }
}

I would limit the initialization in the constructor.

like image 166
AxelH Avatar answered Sep 20 '22 13:09

AxelH