Search code examples
javastaticinstanceforward

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?


Solution

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