幾個問題(--------)父子類靜態變量、靜態代碼塊、非靜態代碼塊、構造函數

 
Java代碼
  1. class Parent{     
  2.     static String name = "hello";     
  3.     static {     
  4.         System.out.println("parent static block");     
  5.     }   
  6.     {   
  7.         System.out.println("parent block");    
  8.     }   
  9.     public Parent(){     
  10.         System.out.println("parent constructor");     
  11.     }     
  12. }     
  13.      
  14. class Child extends Parent{     
  15.     static String childName = "hello";     
  16.     static {     
  17.         System.out.println("child static block");     
  18.     }   
  19.     {   
  20.         System.out.println("child block");    
  21.     }     
  22.     public Child(){     
  23.         System.out.println("child constructor");     
  24.     }     
  25. }     
  26.      
  27. public class StaticIniBlockOrderTest {     
  28.      
  29.     public static void main(String[] args) {     
  30.         new Child();//語句(*)     
  31.     }     
  32. }   
問題:當執行完語句(*)時,打印結果是什麼順序?爲什麼?
解答:當執行完語句(*)時,打印結果是這樣一個順序:parent static block,child static block,parent  block,parent constructor,child  block,child constructor。
分析:當執行new Child()時,它首先去看父類裏面有沒有靜態代碼塊,如果有,它先去執行父類裏面靜態代碼塊裏面的內容,當父類的靜態代碼塊裏面的內容執行完畢之後,接着去執行子類(自己這個類)裏面的靜態代碼塊,當子類的靜態代碼塊執行完畢之後,它接着又去看父類有沒有非靜態代碼塊,如果有就執行父類的非靜態代碼塊,父類的非靜態代碼塊執行完畢,接着執行父類的構造方法;父類的構造方法執行完畢之後,它接着去看子類有沒有非靜態代碼塊,如果有就執行子類的非靜態代碼塊。子類的非靜態代碼塊執行完畢再去執行子類的構造方法,這個就是一個對象的初始化順序。

總結:對象的初始化順序:首先執行父類靜態的內容,父類靜態的內容執行完畢後,接着去執行子類的靜態的內容,當子類的靜態內容執行完畢之後,再去看父類有沒有非靜態代碼塊,如果有就執行父類的非靜態代碼塊,父類的非靜態代碼塊執行完畢,接着執行父類的構造方法;父類的構造方法執行完畢之後,它接着去看子類有沒有非靜態代碼塊,如果有就執行子類的非靜態代碼塊。子類的非靜態代碼塊執行完畢再去執行子類的構造方法。總之一句話,靜態代碼塊內容先執行,接着執行父類非靜態代碼塊和構造方法,然後執行子類非靜態代碼塊和構造方法。
父類Static->子類static->父類缺省{}->父類構造函數->子類缺省{}->子類構造函數
(靜態變量、靜態初始化塊)>(變量、初始化塊)>構造器
注意:子類的構造方法,不管這個構造方法帶不帶參數,默認的它都會先去尋找父類的不帶參數的構造方法。如果父類沒有不帶參數的構造方法,那麼子類必須用supper關鍵子來調用父類帶參數的構造方法,否則編譯不能通過。
 
Java代碼
  1. class Parent {   
  2.     // 靜態變量   
  3.     public static String p_StaticField = "父類--靜態變量";   
  4.     // 變量   
  5.     public String p_Field = "父類--變量";   
  6.   
  7.     // 靜態初始化塊   
  8.     static {   
  9.         System.out.println(p_StaticField);   
  10.         System.out.println("父類--靜態初始化塊");   
  11.     }   
  12.   
  13.     // 初始化塊   
  14.     {   
  15.         System.out.println(p_Field);   
  16.         System.out.println("父類--初始化塊");   
  17.     }   
  18.   
  19.     // 構造器   
  20.     public Parent() {   
  21.         System.out.println("父類--構造器");   
  22.     }   
  23. }   
  24.   
  25. public class SubClass extends Parent {   
  26.     // 靜態變量   
  27.     public static String s_StaticField = "子類--靜態變量";   
  28.     // 變量   
  29.     public String s_Field = "子類--變量";   
  30.     // 靜態初始化塊   
  31.     static {   
  32.         System.out.println(s_StaticField);   
  33.         System.out.println("子類--靜態初始化塊");   
  34.     }   
  35.     // 初始化塊   
  36.     {   
  37.         System.out.println(s_Field);   
  38.         System.out.println("子類--初始化塊");   
  39.     }   
  40.   
  41.     // 構造器   
  42.     public SubClass() {   
  43.         System.out.println("子類--構造器");   
  44.     }   
  45.   
  46.     // 程序入口   
  47.     public static void main(String[] args) {   
  48.         new SubClass();   
  49.     }   
  50. }  
class Parent {
	// 靜態變量
	public static String p_StaticField = "父類--靜態變量";
	// 變量
	public String p_Field = "父類--變量";

	// 靜態初始化塊
	static {
		System.out.println(p_StaticField);
		System.out.println("父類--靜態初始化塊");
	}

	// 初始化塊
	{
		System.out.println(p_Field);
		System.out.println("父類--初始化塊");
	}

	// 構造器
	public Parent() {
		System.out.println("父類--構造器");
	}
}

public class SubClass extends Parent {
	// 靜態變量
	public static String s_StaticField = "子類--靜態變量";
	// 變量
	public String s_Field = "子類--變量";
	// 靜態初始化塊
	static {
		System.out.println(s_StaticField);
		System.out.println("子類--靜態初始化塊");
	}
	// 初始化塊
	{
		System.out.println(s_Field);
		System.out.println("子類--初始化塊");
	}

	// 構造器
	public SubClass() {
		System.out.println("子類--構造器");
	}

	// 程序入口
	public static void main(String[] args) {
		new SubClass();
	}
}

運行一下上面的代碼,結果馬上呈現在我們的眼前:
  1. 父類--靜態變量
  2. 父類--靜態初始化塊
  3. 子類--靜態變量
  4. 子類--靜態初始化塊
  5. 父類--變量
  6. 父類--初始化塊
  7. 父類--構造器
  8. 子類--變量
  9. 子類--初始化塊
  10. 子類--構造器
 
可是靜態代碼塊真的會一定在非靜態代碼塊之前執行嗎?
Java代碼
  1. public class ExA {   
  2.     private static ExA a = new ExA();   
  3.     static {   
  4.         System.out.println("父類--靜態代碼塊");   
  5.     }   
  6.   
  7.     public ExA() {   
  8.         System.out.println("父類--構造函數");   
  9.     }   
  10.   
  11.     {   
  12.         System.out.println("父類--非靜態代碼塊");   
  13.     }   
  14.   
  15.     public static void main(String[] args) {   
  16.         new ExB();   
  17.     }   
  18. }   
  19.   
  20. class ExB extends ExA {   
  21.     private static ExB b = new ExB();   
  22.     static {   
  23.         System.out.println("子類--靜態代碼塊");   
  24.     }   
  25.     {   
  26.         System.out.println("子類--非靜態代碼塊");   
  27.     }   
  28.   
  29.     public ExB() {   
  30.         System.out.println("子類--構造函數");   
  31.     }   
  32. }  
public class ExA {
	private static ExA a = new ExA();
	static {
		System.out.println("父類--靜態代碼塊");
	}

	public ExA() {
		System.out.println("父類--構造函數");
	}

	{
		System.out.println("父類--非靜態代碼塊");
	}

	public static void main(String[] args) {
		new ExB();
	}
}

class ExB extends ExA {
	private static ExB b = new ExB();
	static {
		System.out.println("子類--靜態代碼塊");
	}
	{
		System.out.println("子類--非靜態代碼塊");
	}

	public ExB() {
		System.out.println("子類--構造函數");
	}
}

執行結果
=====
父類--非靜態代碼塊
父類--構造函數
父類--靜態代碼塊
父類--非靜態代碼塊
父類--構造函數
子類--非靜態代碼塊
子類--構造函數
子類--靜態代碼塊
父類--非靜態代碼塊
父類--構造函數
子類--非靜態代碼塊
子類--構造函數
=====
可以發現非靜態代碼塊並不是一定在靜態代碼塊之後執行的。
我認爲此時private static ExA a = new ExA()是靜態變量。而java裏面靜態變量與靜態代碼塊是按代碼先後順序執行。所以就導致非靜態代碼塊在靜態代碼塊之前執行。
 
 
發佈了137 篇原創文章 · 獲贊 6 · 訪問量 33萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章