關於類加載的時候,static代碼塊中可以賦值但不能引用的問題
類加載過程:
先看代碼:
class StaticTest{
static {
a=10;
System.out.println(a);//報錯:Illegal forward reference
}
static int a=1;
public static void main(String[] args) {
StaticTest staticTest = new StaticTest();
}
}
編譯不通過,報錯信息說非法的前向引用
,因為對於a的聲明在下面的靜態變量中,屬於語法錯誤,jvm編譯不通過。
如果去掉輸出這句,變成下面的代碼:
class StaticTest{
static {
a=10;
}
static int a=1;
public static void main(String[] args) {
StaticTest staticTest = new StaticTest();
System.out.println(a);
}
}
輸出結果為:1
問題:為什么a還沒有被聲明就可以被賦值,為什么不報錯?
答:
1.類加載的時候在連接
階段的准備
中,做了下面的事情:
為類的靜態變量
分配內存
並設置默認初始值
,這些變量所使用的內存都將在方法區
中進行分配。
注意:
這時候進行內存分配的僅包括類變量(static),而不包括實例變量,實例變量會在對象實例化的時候隨對象一起分配到堆中。
這些內存都將在方法區中分配
非常量(final)的靜態數據類型被默認賦對應類型的零值(如0、0L、null、false等),而不是程序中顯示的賦值。
准備階段檢測到了a
為int
,分配內存並為a
賦初值0
。
2.然后進入初始化階段之后,對靜態代碼塊執行初始化,靜態變量顯示初始化。
初始化的順序為代碼排列順序
。如靜態代碼塊在靜態變量聲明前,靜態變量a在靜態代碼塊和靜態變量中分別做了賦值,則a先被靜態代碼塊賦值,后被靜態變量賦值語句賦值。並且靜態語句塊只能訪問到定義在靜態語句塊之前的變量,定義在它之后的變量,在前面的靜態語句塊可以賦值,但是不能訪問
。
所以說初始化之前a=0
,先執行static代碼塊,a=10
;然后執行靜態變量,a=1
;