類的初始化,包括生成對象的初始化和類的靜態塊的實例化。
初始化觸發的時機: 類被直接引用(主動引用)的時候。
主動引用
主動引用的情形有:
1. 使用new關健字實例化對象
2. 使用類的靜態變量
3. 使用類的靜態方法
4. 使用反射機制調用上述操作
5. 程序入口 (調用main方法)
初始化順序是:
靜態塊 ---> 非靜態塊 ---> 構造函數。
如果有超類,則初始化順序是:
父類靜態塊--->子類靜態塊--->父類非靜態塊--->父類構造函數--->子類非靜態塊--->子類構造函數
Example:
public class ObjectInitialTest {
public static void main(String[] args) {
System.out.println("---Initialize new Class---");
Father c = new Child();
System.out.println("---Execute chlid class method---");
Child.execute();
}
}
class Child extends Father {
static {
System.out.println("Child static block");
}
{
System.out.println("Child block");
}
public Child(){
System.out.println("Child created");
}
public static void execute() {
System.out.println("Child execute");
}
}
class Father {
static {
System.out.println("Father static block");
}
{
System.out.println("Father block");
}
public Father(){
System.out.println("Father created");
}
}
執行Father c = new Child()輸出爲:
---Initialize new Class---
Father static block
Child static block
Father block
Father created
Child block
Child created
執行Child.execute()輸出爲:
---Execute chlid class method---
Father static block
Child static block
Child execute
執行 Father c = new Child();Child.execute();輸出:
---Initialize new Class---
Father static block
Child static block
Father block
Father created
Child block
Child created
---Execute child class method---
Child execute
由上述結果可知,類的靜態塊,只初始化一次。
結論:
在類的初始化時,只會初始化類的靜態塊和靜態賦值語句,也就是static修飾的代碼塊,沒有static修飾的代碼塊在對象實例化時才執行。
被動引用
被動引用不會觸發類的初始化。
被動引用的情形:
1.引用父類的靜態字段,只會初始化父類,不會初始化子類。
2.引用類的常量,不會引起類的初始化。
類的卸載
在類使用完之後,滿足下面的情形,會被卸載:
1. 該類在堆中的所有實例都已被回收,即在堆中不存在該類的實例對象。
2. 加載該類的classLoader已經被回收。
3. 該類對應的Class對象沒有任何地方可以被引用,通過反射訪問不到該Class對象。
如果類滿足卸載條件,JVM就在GC的時候,對類進行卸載,即在方法區清除類的信息。
總結
Java的類對象基本上都是在jvm的堆區中創建,在創建對象之前,會觸發類加載(加載、連接、初始化),當類初始化完成後,根據類信息在堆區中實例化類對象,初始化非靜態變量、非靜態代碼以及默認構造方法,當對象使用完之後會在合適的時候被jvm垃圾收集器回收。
對象的生命週期只是類的生命週期中使用階段的主動引用的一種情況(即實例化類對象)。而類的整個生命週期則要比對象的生命週期長的多。