類加載:
在Java代碼中,類型的加載、連接與初始化過程都是在程序運行期間完成的。提供了更大靈活性的同時,也增加了更多的可能性。
- 加載:把二進制形式的Java類型讀入java虛擬機中
- 連接
驗證:確保被加載類的正確性
準備:爲類的靜態變量分配內存,並將其初始化爲默認值。在到達初始化之前,類變量都沒有初始化爲真正的初始值
解析:解釋過程就是在類型的常量池中尋找類、接口、字段和方法的符號引用,把這些符合引用替換成直接引用 - 初始化:爲類的靜態變量賦予正確的初始值,每個類只會被初始化一次
- 使用(實例化)
爲新的對象分配內存;爲實例變量賦默認值;爲實例變量賦正確的初始值;java編譯器爲它編譯的每一個類都至少生成一個實例初始化方法,在java的class文件中,這個實例化初始化方法稱爲。針對源代碼中的每一個類的構造法方法,java編譯器都產生一個方法 - 垃圾回收和對象終結(卸載)
java程序對類的使用方式可分爲兩種
主動使用、被動使用
所用的java虛擬機實現必須在每個類或接口被java程序首次主動使用時,才初始化他們
主動使用(七種)
- 創建類的實例
- 訪問某個類或者接口的靜態變量,或者對該靜態變量賦值
- 調用類的靜態方法
- 反射(如Class.forName(“XXX.XXX”))
- 初始化一個類的子類
- Java虛擬機啓動時被標明爲啓動類的類(Java Test)
- JDK1.7開始提供的動態語言支持:java.lang.invoke.MethodHandle實例的解析結果REF_getStatic.RF_putStatic,REF_invokeStatic句柄對應的類沒有初始化,則進行初始化
除了以上七種情況,其他使用java類的方式都被看作是對類的被動使用,都不會導致類的初始化
/**
* 案例:驗證初始化順序
* 代碼在1處未註釋,輸出1,1
* 代碼在2處未註釋時,輸出1,0
* 原因代碼初始化的順序是按照代碼在類中從上到下的順序進行賦值,所以情況2輸出j的結果
* 爲重新賦值
*/
public class Test1 {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
System.out.println(Singleton.i);
System.out.println(Singleton.j);
}
}
class Singleton {
public static int i;
//1.
public static int j = 0;
private static Singleton singleton = new Singleton();
public Singleton() {
i++;
j++;
}
//2.
// public static int j = 0;
public static Singleton getInstance() {
return singleton;
}
}