2

There is well known example from JLS about incorrect forward reference error:

class Test1 {
   int i = j; // compile-time error:
   // incorrect forward reference
   int j = 1;
}

OK, I said, and apply well-known "hack" with keyword this:

class Test1 {
    int i = ++this.j;
    {
// line#4: System.out.println("j = " + j); // compile-time error: illegal forward reference
        System.out.println("j = " + this.j);
    }
    int j = this.j + 1;
    {
        System.out.println("j = " + j);
    }
}

Output will be:

j = 1
j = 2

Who can explain, why I can not access to variable j in line #4?

Is variable j initialized in this line or not?

If it isn't, how I can get value 1 in this.j and 2 on next step?

If if it is, why I can't get access via simple name?

Andremoniy
  • 34,031
  • 20
  • 135
  • 241

2 Answers2

1

It looks like what is happening is similar to what's happening in this question. If you manage to work around the language restrictions and make a reference to an uninitialized variable, it will have it's default value (0 in the case of int).

So in this case, you call int i = ++this.j. Since isn't yet initialized, it takes value 0, which is then incremented. On your next call, it preserves the value it had before and adds one to it.

I found another answer which goes into more detail about the restrictions on initialization. The key part is this

The declaration of a member needs to appear textually before it is used only if the member is an instance (respectively static) field of a class or interface C and all of the following conditions hold

...

  • The usage is via a simple name

So basically, what you're doing is allowed just because the language designers didn't explicitly forbid it.

To deal with the other part of your question, I'll reference the Java documentation.

The Java compiler copies initializer blocks into every constructor.

So the initialization code you wrote happens in the constructor of the object. When the object is created, both variables are initialized with values of 0, after which your code runs to modify those values. So no, the line int i = ++this.j; doesn't initialize j. That happens automatically before that line is reached.

resueman
  • 10,572
  • 10
  • 31
  • 45
0

Q.Is variable j initialized in this line or not?**

Yes it is initialized as can be seen in the below class file of your java code.

// Compiled from Test1.java (version 1.6 : 50.0, super bit)
public class com.test.java.Test1 {

  // Field descriptor #6 I
  int i;

  // Field descriptor #6 I
  int j;

  // Method descriptor #9 ()V
  // Stack: 4, Locals: 1
  public Test1();
     0  aload_0 [this]
     1  invokespecial java.lang.Object() [11]
     4  aload_0 [this]
     5  aload_0 [this]
     6  dup
     7  getfield com.test.java.Test1.j : int [13]
    10  iconst_1
    11  iadd
    12  dup_x1
    13  putfield com.test.java.Test1.j : int [13]
    16  putfield com.test.java.Test1.i : int [15]
    19  aload_0 [this]
    20  aload_0 [this]
    21  getfield com.test.java.Test1.j : int [13]
    24  iconst_1
    25  iadd
    26  putfield com.test.java.Test1.j : int [13]
    29  return
      Line numbers:
        [pc: 0, line: 4]
        [pc: 4, line: 5]
        [pc: 19, line: 10]
        [pc: 29, line: 4]
      Local variable table:
        [pc: 0, pc: 30] local: this index: 0 type: com.test.java.Test1
}

Coming to your question as to why you cannot access j with simple name, it may have to do with how the compiler intelligently reorganizes and substitutes direct access to j with this.j. This looks like it doesnot happen when you try to access it in the initialization block (reasons not known to me) but the below code works with direct reference (may be because compiler smartly puts this referenece when we try to access j)

public Test1() {
        System.out.println(j);
    }
    int i = ++this.j;
    {       
        // line#4: System.out.println("j = " + j); // compile-time error: illegal forward reference
        //System.out.println("j = " + this.j);
    }
    int j = this.j + 1;
Manjunath
  • 1,685
  • 9
  • 9