Java建構函式的繼承
專家讀書筆記,希望能夠對大家學習java有所幫助
"每個子類構造方法的第一條語句,都是隱含地呼叫super(),如果父類沒有這種形式的建構函式,那麼在編譯的時候就會報錯。"
這句話怎麼理解
所有程式碼都經過測試,測試環境:
java version "1.4.0-rc "
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-rc-b91)
Java HotSpot(TM) Client VM (build 1.4.0-rc-b91, mixed mode)
如大家發現任何錯誤,或有任何意見請不吝賜教。
預設建構函式的問題:base類是父類,derived類是子類,首先要
說明的是由於先有父類後有子類,所以生成子類之前要首先有父類。
class是由class的建構函式constructor產生的,每一個class都有
建構函式,如果你在編寫自己的class時沒有編寫任何建構函式,那麼
編譯器為你自動產生一個預設default建構函式。這個default建構函式
實質是空的,其中不包含任何程式碼。但是一牽扯到繼承,它的問題就出現
了。
如果父類base class只有預設建構函式,也就是編譯器自動為你產生的。
而子類中也只有預設建構函式,那麼不會產生任何問題,因為當你試圖產生
一個子類的例項時,首先要執行子類的建構函式,但是由於子類繼承父類,
所以子類的預設建構函式自動呼叫父類的預設建構函式。先產生父類的例項,
然後再產生子類的例項。如下:
class base{
}
class derived extends base{
public static void main(String[] args){
derived d=new derived();
}
}
下面我自己顯式地加上了預設建構函式:
class base{
base(){
System.out.println( "base constructor ");
}
}
class derived extends base{
derived(){
System.out.println( "derived constructor ");
}
public static void main(String[] args){
derived d=new derived();
}
}
執行結果如下:說明了先產生base class然後是derived class。
base constructor
derived constructor
我要說明的問題出在如果base class有多個constructor
而derived class也有多個constructor,這時子類中的建構函式預設
呼叫那個父類的建構函式呢?答案是呼叫父類的預設建構函式。
但是不是編譯器自動為你生成的那個預設建構函式而是你自己顯式地
寫出來的預設建構函式。
class base{
base(){
System.out.println( "base constructor ");
}
base(int i){
System.out.println( "base constructor int i ");
}
}
class derived extends base{
derived(){
System.out.println( "derived constructor ");
}
derived(int i){
System.out.println( "derived constructor int i ");
}
public static void main(String[] args){
derived d=new derived();
derived t=new derived(9);
}
}
D:"java"thinking"think6> java derived
base constructor
derived constructor
base constructor
derived constructor int i
如果將base 類的建構函式註釋掉,則出錯。
class base{
// base(){
// System.out.println( "base constructor ");
// }
base(int i){
System.out.println( "base constructor int i ");
}
}
class derived extends base{
derived(){
System.out.println( "derived constructor ");
}
derived(int i){
System.out.println( "derived constructor int i ");
}
public static void main(String[] args){
derived d=new derived();
derived t=new derived(9);
}
}
D:"java"thinking"think6> javac derived.java
derived.java:10: cannot resolve symbol
symbol : constructor base ()
location: class base
derived(){
^
derived.java:13: cannot resolve symbol
symbol : constructor base ()
location: class base
derived(int i){
2 errors
說明子類中的建構函式找不到顯式寫出的父類中的預設
建構函式,所以出錯。
那麼如果你不想子類的建構函式呼叫你顯式寫出的父類中的預設
建構函式怎麼辦呢?
如下例:
class base{
// base(){
// System.out.println( "base constructor ");
// }
base(int i){
System.out.println( "base constructor int i ");
}
}
class derived extends base{
derived(){
super(8);
System.out.println( "derived constructor ");
}
derived(int i){
super(i);
System.out.println( "derived constructor int i ");
}
public static void main(String[] args){
derived d=new derived();
derived t=new derived(9);
}
}
D:"java"thinking"think6> java derived
base constructor int i
derived constructor
base constructor int i
derived constructor int i
super(i)表示父類的建構函式base(i)請大家注意
一個是super(i)一個是super(8)。
大家想想是為什麼??
結論:子類如果有多個建構函式的時候,父類要麼沒有建構函式,
讓編譯器自動產生,那麼在執行子類建構函式之前先執行編
譯器自動產生的父類的預設建構函式;要麼至少要有一個顯
式的預設建構函式可以讓子類的建構函式呼叫。
java建構函式的呼叫順序:
當一個複雜的物件被構造時,它的建構函式按下面的順序被呼叫(that the order of constructor calls for a complex object is as follows)
1.其基類(base-class)的建構函式被呼叫,這個步驟以遞迴的方式重複,所以最底層(the root ofhierarchy)的建構函式首先被執行,然後是它上一層派生類(the next-derived class)...直到最頂層的派生類(themost-derived class).
The base-class constructor is called. Thisstep is repeated recursively such that the root of the hierarchy isconstructed first, followed by the next-derived class, etc., until themost-derived class is reached.)
2.如果有包含關係(composition),那麼它的成員物件按照宣告的順序被構造.
Member initializers are called in the order of declaration.
3.派生類建構函式的內容(body)被執行.
The body of the derived-class constructor is called.
一個例項:
Cake(){System.out.println("Cake()");}
}
class Meal {
Meal() { System.out.println("Meal()"); }
}
class Bread {
Bread() { System.out.println("Bread()"); }
}
class Cheese {
Cheese() { System.out.println("Cheese()"); }
}
class Lettuce {
Lettuce() { System.out.println("Lettuce()"); }
}
class Lunch extends Meal {
Lunch() { System.out.println("Lunch()"); }
}
class PortableLunch extends Lunch {
//if make derived-class object as the menber of the base-class will lead a infinite
//loop and program will stop because of the memory consumed
//private Sandwich s=new Sandwich();
private Cake a=new Cake();
PortableLunch() { System.out.println("PortableLunch()");}
}
public class Sandwich extends PortableLunch
{
private Bread b = new Bread();
private Cheese c = new Cheese();
private Lettuce l = new Lettuce();
public Sandwich() {
System.out.println("Sandwich()");
}
public static void main(String[] args) {
new Sandwich();
}
}
輸出:
Meal()
Lunch()
Cake()
PortableLunch()
Bread()
Cheese()
Lettuce()
Sandwich()
main()函式中要構造一個Sandwich的物件,呼叫(並不是執行)它基類PortableLunch的建構函式,PortableLunch又遞迴的呼叫,然後是Meal,Meal是繼承的最底層的基類(不算Object)所以它的建構函式首先被執行,然後按次序返回到Lunch,PortableLunch,但在PortableLunch的建構函式被執行之前,它的成員物件Cakea先按照宣告的順序被構造.然後執行PortableLunch(),接著是Sandwich的成員物件,最後是Sandwich().
注:被註釋掉的程式碼,將base-class的物件作為derive-class的成員物件,這樣會遞迴無法結束,最後程式因堆疊耗盡而結束(Exception in thread main java.lang.StackOverflowError).
相關文章
- Java建構函式的繼承問題Java函式繼承
- js建構函式的繼承JS函式繼承
- 繼承中的建構函式繼承函式
- Javascript繼承2:建立即繼承—-建構函式繼承JavaScript繼承函式
- C#建構函式繼承C#函式繼承
- 建構函式的繼承問題 (轉)函式繼承
- 建構函式、原型、原型鏈、繼承函式原型繼承
- 建構函式的prototype與各種繼承函式繼承
- javascript建構函式的繼承簡單介紹JavaScript函式繼承
- [JavaScript]原型、原型鏈、建構函式與繼承JavaScript原型函式繼承
- 子類繼承父類的建構函式(方法)嗎?繼承函式
- JavaScript物件導向之二(建構函式繼承)JavaScript物件函式繼承
- javascript非建構函式繼承簡單介紹JavaScript函式繼承
- javascript物件導向程式設計的建構函式的繼承JavaScript物件程式設計函式繼承
- 關於C#中建構函式的繼承的問題C#函式繼承
- Javascript物件導向程式設計(二):建構函式的繼承JavaScript物件程式設計函式繼承
- javascript物件導向程式設計的非建構函式的繼承JavaScript物件程式設計函式繼承
- js 使用建構函式和原型鏈實現繼承操作JS函式原型繼承
- 繼承與派生,多繼承,函式過載,建構函式呼叫順序 靜態多型和動態多型繼承函式多型
- es5建構函式,es6類和類的繼承函式繼承
- Javascript物件導向程式設計(三):非建構函式的繼承JavaScript物件程式設計函式繼承
- JavaScript中的函式繼承JavaScript函式繼承
- 在 C++ 中子類繼承和呼叫父類的建構函式方法C++繼承函式
- 在C++中子類繼承和呼叫父類的建構函式方法C++繼承函式
- c# abstract抽象類與繼承類子類的建構函式_baseC#抽象繼承函式
- Java的建構函式Java函式
- c# 繼承派生類的預設建構函式的初始化次序C#繼承函式
- 區分:派生類指定基類建構函式、繼承構造、委託構造函式繼承
- java容器類的繼承結構Java繼承
- 《從零開始學Swift》學習筆記(Day43)——建構函式繼承Swift筆記函式繼承
- java——繼承遇到構造方法Java繼承構造方法
- Java泛型建構函式Java泛型函式
- Java建構函式詳解Java函式
- Java的繼承Java繼承
- java之繼承中的構造方法Java繼承構造方法
- Java的預設建構函式呼叫Java函式
- 在建構函式內使用call()或apply()實現繼承函式APP繼承
- 預設建構函式、引數化建構函式、複製建構函式、解構函式函式