Why do two programs have forwarding errors, but the third does not?

The following does not compile by transmitting an “illegal direct appeal” 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 compiles:

 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, passing the message "illegal direct appeal":

 class InstanceInitialisation2 { private String testString1; { testString1 = testString2; } private String testString2; public static void main(String args[]) { new InstanceInitialisation2(); } } 

Why don't StaticInitialisation and InstanceInitialisation2 compile, but does InstanceInitialisation1 do?

+53
java static instance forward
Jun 15 '15 at 6:02
source share
4 answers

This is described in section 8.3.3 of the JLS:

The use of class variables whose declarations appear in the text after use are sometimes limited, although these class variables are in scope (§6.3). In particular, this is a compile-time error if all of the following conditions are true:

  • A class variable declaration in a class or C interface appears after using the class variable text

  • Usage is a simple name either in the initializer of a variable of class C or in the static initializer of C;

  • Use is not on the left side of the task;

  • C is the innermost class or interface that spans usage.

The use of instance variables whose declarations appear in the text after use are sometimes limited, although these instance variables are in scope. In particular, this is a compile-time error if all of the following conditions are true:

  • An instance variable declaration in a class or C interface appears after using an instance variable text

  • Usage is a simple name either in the initializer of the instance variable C, or in the initializer of the instance C;

  • Use is not on the left side of the task;

  • C is the innermost class or interface that spans usage.

In your second case, using is not a simple name - you have this explicitly. This means that it does not match the second pool in the second list above, so there are no errors.

If you change it to:

 System.out.println("Test string is: " + testString); 

... then it will not 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 the way it happens.

+57
Jun 15 '15 at 6:19 06:19
source share

Let's take a look at these two examples, I think it will allow you to understand.

 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 that the sequence is this.

  • A static variable will be created, but will not be initialized.

  • Static initialization will be performed in accordance with the specified sequence.

  • A non-static variable will be created, but will not be initialized.
  • Non-static initialization will be performed in accordance with this sequence.

In order, I mean appearing in the code.

I think these steps answer your two not working example StaticInitialisation and InstanceInitialisation2

But in the case of your second working InstanceInitialisation1 example, with the this keyword, you really help the compiler lose sight of the text hierarchy. The same thing happens in the case of static , when I call InstanceAndSataticInit.testStringStatic in my first InstanceAndSataticInit example

+2
Jun 15 '15 at 6:36
source share

A simple reason is too expensive or impossible to analyze and ban all direct links. eg.

 { print( getX(); ); // this.x print( that().x ); // this.x } int x; int getX(){ return x; } This that(){ return this; } 

The specification settles on the prohibition of some simple cases that indicate errors of the ordinary programmer.

See also. Does a recursive initializer work when I add "his"?

+2
Jun 15 '15 at 12:15
source share

Here we need to understand that in the second code fragment you use a block and this is a keyword .

  • A block is executed if an object is created.
  • This means that the object is created in the heap area.
  • Externally, use this keyword to get the value of an instance variable.
  • This creates an object with default values ​​that will be returned as a value.
  • Without using this keyword, you also cannot compile the second snippet.
+1
Jun 15 '15 at 6:23
source share



All Articles