2014-08-29 18 views
2

有衆所周知exampleJLSincorrect forward reference錯誤:不正確的搞怪問題前向參考

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

OK,我說,並運用著名的 「黑客」 與關鍵字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); 
    } 
} 

輸出將是:

j = 1 
j = 2 

誰能解釋,爲什麼我不能訪問第4行的變量j

變量j是否在此行中初始化?

如果不是,我如何在this.j2中獲得價值1下一步?

如果是,爲什麼我無法通過simple name訪問?

+0

你確定class test1沒有成員變量j嗎?看起來很腥 – coffeeaddict 2014-08-29 14:10:26

+1

@coffeeaddict去編譯它...我不明白你的問題。是的!它在我的代碼中被聲明。 – Andremoniy 2014-08-29 14:11:28

+0

這是一個規則,不是嗎?在你的鏈接頁面,規則#3:'用法是通過一個簡單的名字'它是如此設計的,不是嗎? – Kent 2014-08-29 14:20:43

回答

1

看起來發生了什麼類似於this question中發生的情況。 如果您設法解決語言限制並對未初始化的變量進行引用,則它將具有默認值(在int的情況下爲0)。所以在這種情況下,你調用`int i = ++ this.j「。由於尚未初始化,因此它的值爲0,然後遞增。在下次調用時,它保留它的值之前和廣告一個吧。

我發現another answer其進入有關初始化限制的更多細節,關鍵部分是

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

因此,基本上,你在做什麼是允許的,只是因爲語言設計者沒有明確禁止它。

要處理您的問題的其他部分,我會參考Java documentation

The Java compiler copies initializer blocks into every constructor.

所以你寫的初始化代碼發生在對象的構造函數中。創建對象時,兩個變量都將初始化爲0,在此之後,您的代碼將運行以修改這些值。所以不行,行int i = ++this.j;不初始化j。那個行在到達之前自動發生。

+0

@Andremoniy他做到了。使用'j'是一個簡單的名字。 – 2014-08-29 14:43:58

0

Q.Is變量j在此行中初始化或沒有?**

是因爲可以在Java代碼的下方類文件可以看出它被初始化。

// 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 
} 

來到你的問題,爲什麼你不能用簡單的名稱訪問j時,會可能與編譯器如何聰明地整理和替代品與this.j.直接進入到j做這看起來像是當你嘗試在初始化塊中訪問它時沒有發生(原因我不知道),但下面的代碼與直接引用一起工作(可能是因爲當我們嘗試訪問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;