jvm之類加載器(1)
來自: http://www.cnblogs.com/think-in-java/p/5178383.html
首先我們先看一個示例程序:
package com.tfdd.test; /** * @desc 類加載校驗 * @author chenqm * @date 2016年2月2日 */ class Singleton{ private static Singleton singleton = new Singleton(); public static int count1 ; public static int count2 = 0; private Singleton(){ count1++; count2++; } public static Singleton getInstance(){ return singleton; } } public class SingletonTest { public static void main(String[] args) { Singleton singleton = Singleton.getInstance(); System.out.println(singleton.count1); System.out.println(singleton.count2); } }
猜猜輸出的結果是什么?據說80%的java程序猿都會犯的錯誤!
10
就是這樣一個結果,我們先不說為什么。接著講我們的類加載器.
類的加載大致分為三個部分:加載,連接,初始化。
加載 :查找并加載類的二進制數據
連接 :1.驗證(確保被加載類的準確性) 2.準備(為類的靜態變量分配內存,并將其初始化為默認值) 3.解析(將類中的符號引用轉化為直接引用)
初始化 :為類的靜態變量賦予正確的初始值(即賦上我們給出的值)
然后我們再看看java程序對類的使用方式:主動使用和被動使用。請注意下面我說的這句話
所有的JAVA虛擬機實現必須在每個類或接口被JAVA程序“首次主動使用”時才初始化他們。
那么什么叫主動使用?基本上分為6種情況:
--創建類的實例
--訪問某個類或接口的靜態變量,或者對該靜態變量賦值
--調用類的靜態方法
--反射
--初始化一個類的子類
--java虛擬機啟動時被標明為啟動類的類
了解了這些知識之后,我現在來回答之前的問題,
Singleton.getInstance(); 調用了類的靜態方法,符合首次主動使用該類的情況!那么我們進入初始化階段。 初始化已經屬于類加載的第三步了,在第二步的連接的準備部分,已經賦過一次默認值了。所以應該是這樣一個過程: 1.singleton = null;count1=0;count1=0 2.singleton = new Singleton(); 此時執行構造函數,結果為count0=1;count1=1 3.count0沒有被我們賦值跳過初始化,count1賦值為0所以結果為count0=1;count1=0 (*注意) 類的靜態變量賦值的順序是按照代碼的書寫的順序執行的。 修改代碼如下:
package com.tfdd.test;/**
- @desc 類加載校驗
- @author chenqm
@date 2016年2月2日 */ class Singleton{ public static int count1 ; public static int count2 = 0; private static Singleton singleton = new Singleton();
private Singleton(){
count1++; count2++;
}
public static Singleton getInstance(){
return singleton;
}
} public class SingletonTest { public static void main(String[] args) { Singleton singleton = Singleton.getInstance(); System.out.println(singleton.count1); System.out.println(singleton.count2); } }</pre>
輸出結果為
1
1