Java類的生命週期,Java對象創建時代碼(靜態方法,成員方法,構造方法等)的加載順序

Java中類的生命週期爲加載連接初始化使用卸載五個過程,如下圖所示:

1.加載

    我們編寫一個java類的代碼,經過編譯之後生成一個後綴名爲.class的文件,java虛擬機就能識別這種文件。java的生命週期就是class文件從加載到消亡的過程。 關於加載,其實,就是從源文件的class文件找到類的信息將其加載到方法區中,然後在堆區中實例化一個java.lang.Class字節碼對象,作爲方法區中這個類的信息的入口。但是這一功能是在JVM之外實現的,主要的原因是方便讓應用程序自己決定如何獲取這個類,在不同的虛擬機實現的方式不一定相同,hotspot虛擬機是採用需要時再加載的方式,也有其他是先預先加載的。 (可以參考深入理解JVM這本書)

2.連接
    連接一般是加載階段和初始化階段交叉進行,過程由以下三部分組成:
    (1)驗證:確定該類是否符合java語言的規範,有沒有屬性和行爲的重複,繼承是否合理,總之,就是保證jvm能夠執行
    (2)準備:主要做的就是爲由static修飾的成員變量分配內存,並設置默認的初始值
        默認初始值如下:

                    1.八種基本數據類型默認的初始值是0
                    2.引用類型默認的初始值是null

                    3.有static final修飾的會直接賦值,例如:static final int x=10;則默認就是10.

   (3)解析:這一階段的任務把類中的符號引用轉換成直接引用,說白了就是JVM會將所有的類或接口名、字段名、方法名轉換爲具體的內存地址。例如在A類的a方法中調用B

public class A {
    B b = new B();
    public void a() {
        b.b();//這行代碼在A類的二進制數據中表示爲符號引用
    }
}

在A類的二進制數據中,包含了一個對B類b()方法的符號引用,它由b()方法的全名和相關描述組成。在解析階段,JVM將這個符號引用替換成爲一個指針,該指針指向B類b()方法在方法區內的內存位置,這個指針就是直接引用。

3.初始化
    初始化這個階段就是將靜態變量(類變量)賦值的過程,即只有static修飾的才能被初始化,執行的順序就是:父類靜態域或着靜態代碼塊,然後是子類靜態域或者子類靜態代碼塊.

4.使用

    在類的使用過程中依然存在以下三步:

    (1)對象實例化:就是執行類中構造函數的內容,如果該類存在父類JVM會通過顯示或者隱示的方式先執行父類的構造函數,在堆內存中爲父類的實例變量開闢空間,並賦予默認的初始值,然後在根據構造函數的代碼內容將真正的值賦予實例變量本身,然後,引用變量獲取對象的首地址,通過操作對象來調用實例變量和方法

    (2)垃圾收集:當對象不再被引用的時候,就會被虛擬機標上特別的垃圾記號,在堆中等待GC回收
    (3)對象的終結:對象被GC回收後,對象就不再存在,對象的生命也就走到了盡頭
5.類卸載
    類卸載即類的生命週期走到了最後一步,程序中不再有該類的引用,該類也就會被JVM執行垃圾回收,從此生命結束…
 

package com.java.oop;
class A{
	static int a;//類變量
	String name;
	int id;
	//靜態代碼塊
	static{
		a=10;
		System.out.println("這是父類的靜態代碼塊"+a);
	}
	//構造代碼塊
	{
		id=11;
		System.out.println("這是父類的構造代碼塊id:"+id);
	}
	A(){
		System.out.println("這是父類的無參構造函數");
	}
	A(String name){
		System.out.println("這是父類的name"+name);
	}
}
class B extends A{
	String name;
	static int b;
	static{
		b=12;
		System.out.println("這是子類的靜態代碼塊"+b);
	}
	B(String name) {
		super();
		this.name = name;
		System.out.println("這是子類的name:"+name);
	}
}
public class TestClassObject08 {
	public static void main(String[] args) {
		B bb=new B("GG");
	}
}

執行結果如下:

這是父類的靜態代碼塊10
這是子類的靜態代碼塊12
這是父類的構造代碼塊id:11
這是父類的無參構造函數
這是子類的name:GG

分析:以上運行結果可知Java對象創建時代碼(靜態方法,成員方法,構造方法等)的加載順序爲:父類的靜態的代碼-->子類的靜態的代碼-->父類內部非靜態代碼-->父類的構造方法-->子類的非靜態代碼-->子類的構造方法.

參考文章:

https://www.cnblogs.com/ipetergo/p/6441310.html

https://blog.csdn.net/qq_42401622/article/details/81190406

https://www.cnblogs.com/9513-/p/8456877.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章