JAVA類加載一道筆試題

初始化

初始化這個階段就是將靜態變量(類變量)賦值的過程,即只有static修飾的才能被初始化,執行的順序就是:父類靜態域或着靜態代碼塊,然後是子類靜態域或者子類靜態代碼塊(靜態代碼塊先被加載,然後再是靜態屬性)
class A {
	static {
		System.out.print("a");//只有在類加載時候會執行一次
	}
 
	public A() {
		System.out.print("x");
	}
 
}
 
class B extends A {
	static {
		System.out.print("b");
	}
 
	public B() {
		System.out.print("y");
	}
}
 
public class Test {
 
	public static void main(String[] args) {
 
		A ab = new B();
		System.out.println();
		ab = new B();
 
	}
 
}

輸出:abxy xy

執行過程:

A ab = new B();

執行時候第一使用到A、B類,JVM發現沒有加載A、B的信息,故先加載,由於B繼承了A類,所以會先加載A再加載B,在加載的過程中會執行static塊完成類的初始化。所以會先輸出ab,此時創建B對象時候,會先執行A的構造方法在執行B的構造方法,故在輸出xy,所以最後輸出abxy

當執行:

ab = new B();

時候發現已經加載過A、B的字節碼了,故不會再加載了,所以不會輸出ab,直接輸出xy即可

如果代碼修改爲:

class A {
	static {
		System.out.print("a");// 只有在類加載時候會執行一次
	}
 
	public A() {
		System.out.print("x");
	}
 
}
 
class B extends A {
	static {
		System.out.print("b");
	}
 
	public B() {
		System.out.print("y");
	}
}
 
public class Test {
 
	public static void main(String[] args) {
 
		B ab = new B(); // 由於A ab = new B()=> B ab = new B()
		System.out.println();
		ab = new B();
	}
}

輸出還是:
abxy
xy

當執行B ab = new B()時候,由於JVM事先就會知道B是繼承至A的,所以需要先加載A,如果不先加載A的話,無法完成子類B的加載!所以類的加載順序和構造器執行順序一致,先父類再子類!

注意:容易糊塗的地方是,以爲B ab =new B();以爲創建B所以先加載B之後再加載A,這種理解就錯誤了,因爲對於對象的創建是從父類開始的!

拓展:非靜態代碼塊的執行順序也是先父類,在子類!但是非靜態代碼塊執行順序在靜態代碼塊之後,構造器之前!靜態代碼塊只會執行一次(類加載時候執行),而非靜態代碼塊會多在創建對象時候多次執行!

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