類的生命周期:
Java類的初始化:
本階段負責為類變量賦正確的初始值。(類變量即靜態變量)
Java編譯器把所有的類變量初始化語句和靜態初始化器通通收集到<clinit>方法中,該方法只能被JVM調用,專門承擔初始化工作。
初始化一個類必須保證其直接超類已被初始化。
並非所有類都擁有<clinit>()方法。以下類不會擁有<clinit>方法:
- 該類既沒有聲明任何類變量,也沒有靜態初始化語句。
- 該類聲明了類變量,但沒有使用類變量初始化語句或靜態初始化語句初始化。
- 該類只包含靜態final變量的類變量初始化語句,並且類變量初始化語句是常量表達式。
Java類初始化的時機:
規范定義類的初始化時機為“initialize on first active use”,即“在首次主動使用時初始化”。裝載和鏈接在初始化之前就要完成。
首次主動使用的情形:
- 創建類的新實例--new,反射,克隆或反序列化;
- 調用類的靜態方法;
- 操作類和接口的靜態字段;(final字段除外)
- 調用Java的特定的反射方法;
- 初始化一個類的子類;
- 指定一個類作為Java虛擬機啟動時的初始化類(含有main方法的啟動類)。
除了以上6種情形,java中類的其他使用方式都是被動使用,不會導致類的初始化。
Java對象初始化:
編譯器為每個類生成至少一個實例初始化方法,即<init>()方法。此方法與源程序里的每個構造方法對應。如果類沒有聲明構造方法,則生成一個默認構造方法,該方法僅調用父類的默認構造方法,同時生成與該默認構造方法對應的<init>()方法。
<init>()方法內容大概為:
- 調用另一個<init>()方法(本類的另外一個<init>()方法或父類的<init>()方法);
- 初始化實例變量;
- 與其對應的構造方法內的字節碼
Java對象初始化的時機:
對象初始化又稱為對象實例化。Java對象在其被創建時初始化。有兩種方式創建Java對象:
一種是顯示對象創建,通過new關鍵字來調用一個類的構造函數,通過構造函數創建一個對象。
一種是隱式對象創建:
- 加載一個包含String字面量的類或接口會引起一個新的String對象創建,除非包含相同字面量的String對象已經在JVM中存在了。
String s1 = "zheng";
- 自動裝箱機制可能會引起一個原子類型的包裝類對象被創建。
Integer iWrapper = 1;
- String連接符也可能會引起新的String或者StringBuilder對象被創建,同時還有可能引起原子類型的包裝對象被創建。
System.out.println("zheng"+1);
對象實例初始化的例子:
public class Base { Base() { preProcess(); } void preProcess() {} }
public class Derived extends Base { public String whenAmISet = "set when declared"; @Override void preProcess() { whenAmISet = "set in preProcess()"; } }
public class Main { public static void main(String[] args) { Derived d = new Derived(); System.out.println( d.whenAmISet ); } }
下面是整個的運行流程:
- 進入Derived類構造函數
- Derived成員變量的內存被分配
- 調用Base類的構造函數
- Base類構造函數調用preProcess()方法
- Derived類的preProcess()方法設置whenAmISet
- Derived類的成員變量初始化被調用
- 執行Derived構造函數體
可以看到在執行完父類的構造函數后,第6步才對Derived類的成員變量初始化。
Java類初始化例子:
import java.util.Map; import java.util.HashMap; import java.util.Collections; public class Singleton { public static Singleton singleton = new Singleton(); public static Map m; static{ m = new HashMap(); } private Singleton(){ initM(); } public static void initM(){ if(null == m){ System.out.println("m 為空"); m = new HashMap(); } m.put("1", "鄭"); m.put("2", "陳"); } public static Singleton getInstance(){ return singleton; } }
public class Main { public static void main(String [] args){ Singleton singleton = Singleton.getInstance(); } }
運行結果輸出m 為空
是因為在類初始化階段先對singleton賦值調用Singleton類構造函數,然后Singleton類構造函數調用initM()方法。但是此時還沒有運行static方法,所以m=null.