天天看點

類的初始化和執行個體初始化

這裡的原理和例子來源自尚矽谷的講師宋紅康(深入了解JVM)和柴林燕(Java面試題),表示非常感謝。

java程式将位元組碼通過類的加載子系統将類的元資訊加載到方法區中,一共有三步,加載,連結,初始化。具體請看深入了解JVM。這裡通過題目示範類的初始化和執行個體初始化。

father類

public class Father{
	private int i = test();
	private static int j = method();
	
	static{
		System.out.print("(1)");
	}
	Father(){
		System.out.print("(2)");
	}
	{
		System.out.print("(3)");
	}
	
	
	public int test(){
		System.out.print("(4)");
		return 1;
	}
	public static int method(){
		System.out.print("(5)");
		return 1;
	}
}
           

son類

public class Son extends Father{
	private int i = test();
	private static int j = method();
	static{
		System.out.print("(6)");
	}
	Son(){
//		super();//寫或不寫都在,在子類構造器中一定會調用父類的構造器
		System.out.print("(7)");
	}
	{
		System.out.print("(8)");
	}
	public int test(){
		System.out.print("(9)");
		return 1;
	}
	public static int method(){
		System.out.print("(10)");
		return 1;
	}
	public static void main(String[] args) {
	}
}
           

若運作son類,輸出的結果為

類的初始化和執行個體初始化

這是為什麼呢,主方法裡面并沒有調用任何函數?這就需要講解一下類的初始化過程了。

類的初始化過程

類的初始化和執行個體初始化

是以當運作主方法時,将son和father類加載進虛拟機的方法區。main方法在son類中,要加載son類的時候需要先加載其父類father,而在初始化son的時候需要先初始化father,在初始化father時,執行方法,指派靜态的類變量的靜态代碼塊。是以就先輸出(5)(1),接下裡初始化son類,也是指派靜态的類變量的靜态代碼塊。是以輸出(10)(6)。

執行個體的初始化過程

在上面代碼的基礎上,修改main方法,加上一下三行代碼

Son s1 = new Son();
		System.out.println();
		Son s2 = new Son();
           

則輸出結果為

類的初始化和執行個體初始化

其中(5)(1)(10)(6)上面為兩個類初始化的輸出結果,主要讨論後面的輸出結果,這就涉及到執行個體的初始化和方法的重寫了。

類的初始化和執行個體初始化
類的初始化和執行個體初始化

分析結果:我們從上知道,執行個體化對象就是調用方法,也就是構造器,**注意:每個構造器不管你加不加都預設有一句super();**也即是說先需要調用父類的構造器。然後在初始化非靜态變量和非靜态代碼塊,最後再執行構造器。是以過程如下

son類

* 子類的執行個體化方法<init>:
 * (1)super()(最前)      (9)(3)(2)
 * (2)i = test();    (9)
 * (3)子類的非靜态代碼塊    (8)
 * (4)子類的無參構造(最後) (7)
           

father類

*  父類的執行個體化方法:
 * (1)super()(最前)
 * (2)i = test();
 * (3)父類的非靜态代碼塊
 * (4)父類的無參構造(最後)
 * 
 * 非靜态方法前面其實有一個預設的對象this
 * this在構造器(或<init>)它表示的是正在建立的對象,因為這裡是在建立Son對象,是以
 * test()執行的是子類重寫的代碼(面向對象多态)
 * 
 * 這裡i=test()執行的是子類重寫的test()方法
 * 
           

根據這個分析可以得出結果。