這個是錯誤的程式碼:
class BB { static int a = 0 ; public BB() { a++ ; System.out.println("执行BB" + a) ; } public void printA() { System.out.println("a= " + a) ; } } public class CC { static { a = new BB() ; a.printA() ; //报错说非法的前向引用 } static BB a = new BB() ; public staic void main(String args[]) { CC c = new CC() ; } }
為什麼我在static程式碼區塊中對a進行了初始化,仍然報錯呢?
原因就涉及了java對於初始化過程中對成員變數的限制:
成員變數a如果滿足如下的4點,就必須在使用前必須對該成員變數進行宣告
設定C為直接包含該成員變數的類別或介面
#如果a出現在C的或靜態成員/非靜態成員初始化或C的靜態或非靜態程式碼區塊中
如果a不是一個賦值不等式的左值
透過簡單名稱來存取
在我自己寫的程式碼中,a.printA() ;出現的位置是CC的靜態程式碼區塊中,透過簡單名稱直接存取(也就是直接使用a), 並且不是賦值不等式的左值,所以會報錯「非法的前向引用」
這個是java語言規範中的原文碼(其中的中文是我自己的標註):
class UseBeforeDeclaration { static { x = 100; // ok - assignment , 赋值表达式的左值 int y = x + 1; // error - read before declaration , 赋值表达式的右值 int v = x = 3; // ok - x at left hand side of assignment , 左值 int z = UseBeforeDeclaration.x * 2; // ok - not accessed via simple name , 是通过类.静态变量 的形式访问, 而非直接简单访问 Object o = new Object() { void foo() { x++; } // ok - occurs in a different class , 不是CC的代码块或成员初始化中,而是在一个全新的内部类的函数中 { x++; } // ok - occurs in a different class , 在一个内部类的代码块中, 和上一个类似 }; } { j = 200; // ok - assignment j = j + 1; // error - right hand side reads before declaration , 第二个右值 int k = j = j + 1; // error - illegal forward reference to j , 第三个是右值 int n = j = 300; // ok - j at left hand side of assignment , 左值 int h = j++; // error - read before declaration , 右值, 并参与了自增运算 int l = this.j * 3; // ok - not accessed via simple name 通过this.j进行访问, 非直接简单访问 Object o = new Object() { void foo() { j++; } // ok - occurs in a different class { j = j + 1; } // ok - occurs in a different class }; } int w = x = 3; // ok - x at left hand side of assignment int p = x; // ok - instance initializers may access static fields static int u = (new Object() { int bar() { return x; } }).bar(); // ok - occurs in a different class static int x; int m = j = 4; // ok - j at left hand side of assignment int o = (new Object() { int bar() { return j; } }).bar(); // ok - occurs in a different class int j; }
非法向前引用的例子:
那麼為什麼類似i= "1234";這樣的程式碼可以呢?
這是因為Java對其中的某些情況做了“特許”,其中有一條是“通過簡單名稱引用的變數可以出現在左值位置,但不能出現在右值的位置”,所以前面的程式碼可以,但System.out.println(i);不行,因為這是一個右值引用。
其目的是避免循環初始化和其他非正常的初始化行為。
什麼是循環引用,看看下面這個例子:
privateinti=j; privateintj=i;
如果沒有前面說的強制檢查,那麼這兩句程式碼就會透過編譯,但是很容易就能看得出來,i和j並沒有真正賦值,因為兩個變數都是未初始化的(Java規定所有變數在使用前都必須初始化)
以上是java報錯非法的前向引用問題怎麼解決的詳細內容。更多資訊請關注PHP中文網其他相關文章!