1. 程式人生 > >java之面向物件:子類物件的例項化過程詳解

java之面向物件:子類物件的例項化過程詳解

在子類建構函式中,發現,訪問子類建構函式時,父類也運行了。原因是什麼呢?

在子類的建構函式裡第一行有一個預設的隱式語句:super()

ExtendsDemo.java

class Fu
{
	Fu()
	{
		System.out.println("fu run");
	}
}
class Zi extends Fu
{
	Zi()
	{
		//super();  //呼叫的是父類中的空引數的建構函式
		System.out.println("zu run");
	}
}
class ExtendsDemo
{
	public static void main(String[] args)
	{
		new Zi();
	}
}

輸出:

我們也可訪問父類中帶有引數的建構函式:

class Fu
{
	Fu(int x)
	{
		System.out.println("fu run");
	}
}
class Zi extends Fu
{
	Zi()
	{
		super(4);  //父類有帶引數的建構函式
		System.out.println("zu run");
	}
}

子類的例項化過程:

子類中所有的建構函式預設都會訪問父類中的空引數的建構函式。當然,如果子類中指定了訪問父類帶引數的建構函式,就不會訪問父類預設的建構函式(好像是廢話哈~~)

這就意味著如果父類中沒有預設的建構函式,子類嘗試呼叫父類的預設建構函式,程式就會報錯:

class Fu
{
	Fu(int x)   //指定了新的建構函式,預設的建構函式就沒有了
	{
		System.out.println("fu run 2");
	}
}
class Zi extends Fu
{
	Zi()
	{
		super(4);  //父類有帶引數的建構函式
		System.out.println("zu run 1");
	}
	Zi(int x)
	{
		//super();  //預設會訪問父類的建構函式
		System.out.println("zu run 2");
	}
}
class ExtendsDemo
{
	public static void main(String[] args)
	{
		new Zi(6);
	}
}

輸出:


所以這時候就需要在子類中指定呼叫父類帶引數的建構函式:

class Fu
{
	Fu(int x)   //指定了新的建構函式,預設的建構函式就沒有了
	{
		System.out.println("fu run 2");
	}
}
class Zi extends Fu
{
	Zi()
	{
		super(4);  //父類有帶引數的建構函式
		System.out.println("zu run 1");
	}
	Zi(int x)
	{
		super(x);  //預設會訪問父類的建構函式
		System.out.println("zu run 2");
	}
}
class ExtendsDemo
{
	public static void main(String[] args)
	{
		new Zi(6);
	}
}

輸出:

為什麼子類預設會訪問父類的預設建構函式呢?

那是因為:子類繼承了父類,獲取到了父類中內容(屬性),所以在使用父類內容之前,要先看父類是如何對自己的內容進行初始化的,所以子類在構造物件時候,必須訪問父類的建構函式,為了完成這個必須的動作,就在子類的建構函式中加入了super()語句、

如果父類中沒有定義空引數建構函式,那麼子類的建構函式必須用super明確要呼叫父類中哪個建構函式,否則子類無法完成初始化。

注意:super語句必須要定義在子類建構函式的第一行,因為父類的初始化動作要先完成。

//----------------------------------------------------------------------------------------------------------------------------------------------------------------

同時子類建構函式如果使用this呼叫了本類建構函式時,那麼super就沒有了,因為super和this都只能定義在第一行,所以只能有一個,但是可以保證的是,子類中肯定會有其他的建構函式訪問父類的建構函式。

class Fu
{
	Fu(int x)   //指定了新的建構函式,預設的建構函式就沒有了
	{
		System.out.println("fu run 2");
	}
}
class Zi extends Fu
{
	Zi()
	{
		super(4);  //父類有帶引數的建構函式
		System.out.println("zu run 1");
	}
	Zi(int x)
	{
		this();
		//super(x);  //預設會訪問父類的建構函式
		System.out.println("zu run 2");
	}
}
class ExtendsDemo
{
	public static void main(String[] args)
	{
		new Zi(6);
	}
}
輸出:

注意的問題:

java中任何類預設會繼承一個根類——Object,主動繼承這個類或者不繼承這個類寫法都可以。

class Fu
{
	Fu()
	{
		super();
		show();
		return;
	}
	
	void show()
	{
		System.out.println("fu show");
	}
}

class Zi extends Fu
{
	int num = 8;
	Zi()
	{
		super();
		System.out.println("zi cons num..."+num);
	}
	void show()
	{
		System.out.println("zi show..."+num);
	}
}

class Demo
{
	public static void main(String[] args)
	{
		Zi z = new Zi();
		z.show();
	}
}


輸出:

物件例項化圖解:

通過super初始化父類內容時,子類的成員變數並未顯示初始化,等super()父類初始化完畢後,才進行子類的成員變數顯式初始化。

物件的例項化過程步驟總結:

Person p = new Person();

1、JVM會讀取指定路徑下的Person.class檔案,並載入進記憶體。並會先載入Person的父類(如果有直接的父類的情況下)

2、在堆記憶體中開闢空間,分配地址。

3、並在物件空間中,對物件中的屬性進行預設初始化。(不是顯式初始化)

4、呼叫對應的建構函式進行初始化。

5、在建構函式中,第一行會先呼叫父類的建構函式進行初始化。

6、父類初始化完畢後,在對子類的屬性進行顯式初始化。

7、再進行子類建構函式的特定初始化。

8、初始化完畢夠,將地址值賦值給引用變數。