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、初始化完畢夠,將地址值賦值給引用變數。