指出下面代碼的結果是什麼:
public class Test{
private static Test test = new Test();
public static int num1;
public static int num2=0;
private Test(){
num1++;
num2++;
}
public static Test getInstance(){
return test;
}
public static void main(String[] args) {
Test test = Test.getInstance();
System.out.println(test.num1);
System.out.println(test.num2);
}
}
這題目主要考察Java的初始化順序的。結果是1,0
分解一下這段代碼執行的過程:
java 代碼
Test test = Test.getInstance();
java虛拟機運作到Test了,于是開始尋找Test,找到了Test.class,然後開始加載,于是開始初始化。
初始化順序的總規則:首先靜态初始化,然後定義初始化,然後是構造函數初始化;
靜态分為兩種:
1、靜态的成員變量
2、靜态代碼塊 static{}
一般來說首先初始化靜态類變量,然後初始化靜态代碼塊。
如果某個類有父類,那麼初始化順序是:
1、對父類進行靜态初始化(初始化父類的靜态成員變量或者靜态代碼塊)
2、對子類進行靜态初始化(初始化子類的靜态成員變量或者靜态代碼塊)
3、對父類進行定義初始化(初始化父類的成員變量)
4、對父類進行構造函數初始化
5、對子類進行定義初始化(初始化子類的成員變量)
6、對子類進行構造函數初始化
注意:jvm隻在首次使用某個類的時候對其類變量進行一次初始化!
回到正題,jvm初始化Test的時候也是按照上面的順序進行的:
1、ClassLoader加載Test.class,這個時候Test.class中的三個靜态變量已經被裝載進記憶體,并分别賦予了初始值null,0,0 (不知道這樣了解對不對)
2、按照順序對Test.class進行靜态初始化,注意這裡隻對所有顯式初始化的變量進行初始化!沒有顯式初始化的變量不再進行 初始化!比如num1沒有被顯式的初始化,不再參與這個初始化過程(不知道這個了解對不對)
是以首先初始化的是:
private static Test test = new Test();
3、初始化test變量的時候調用了Test類的構造函數,在Test構造函數中對兩外兩個靜态變量num1、num2進行了++操作,這個 時候num1和num2的初始值應該都是預設值0!進行++操作後,這個時候num1和num2的值都是1
4、完成了對靜态變量test的初始化後開始初始化num2,這個時候num1=1,但是num2=0(即為結果)。
題目的延伸:
如果把代碼改為:
public class Test {
public static int num1;
public static int num2 = 0;
private static Test test = new Test();
private Test() {
num1++;
num2++;
}
public static Test getInstance() {
return test;
}
public static void main(String[] args) {
Test test = Test.getInstance();
System.out.println(test.num1);
System.out.println(test.num2);
}
}
結果将會是:1,1
因為按照順序,先初始化了num2,後初始化test!
1、裝載Test.class
2、給類變量配置設定空間,賦予初始值
test = null (指向null)
num1 = 0
num2 = 0
3、開始初始化顯式指派的變量(test、num2)
1)初始化num2,将num2指派為0
2)初始化test
(1)對類Test進行初始化,因為類變量隻初始化一次,是以這裡不再需要對test進行初始化了
(2)Test沒有執行個體變量,是以不需要初始化執行個體變量
(3)對Test進行構造函數初始化,對num1和num2進行++操作
(4)初始化完畢,在堆區開辟記憶體空間存儲Test的執行個體。
3)這個時候num1 = 1,num2 = 1
把代碼改為:
public class Test {
private static Test test = new Test();
public int num1;
public int num2 = 0;
private Test() {
num1++;
num2++;
}
public static Test getInstance() {
return test;
}
public static void main(String[] args) {
Test test = Test.getInstance();
System.out.println(test.num1);
System.out.println(test.num2);
}
}
結果将會是:1,1
1、裝載Test.class
2、給類變量配置設定空間,賦予初始值
test = null (指向null)
num1 = 0
num2 = 0
3、開始初始化顯式指派的變量(這裡是test,因為num1和num2都不是靜态的)
1)初始化test
(1)按照初始化順序,構造Test的時候首先初始化類變量,因為類變量隻初始化一次,是以這裡不再需要對test進行初始化了
(2)進行定義初始化,初始化num1 和 num2
(3)對Test進行構造函數初始化,對num1和num2進行++操作
(4)初始化完畢,在堆區開辟記憶體空間存儲Test的執行個體。
3)這個時候num1 = 1,num2 = 1。