1 繼承的概念
如果類 B 具有類 A 的全部屬性和方法,而且又具有自己特有的某些屬性和方法,則把類 A 稱作一般類,把類 B 稱作特殊類。
在面向對象程序設計中運用繼承原則,就是在每個由一般類和特殊類形成的一般 - 特殊結構中,把一般類的對象實例和所有特殊類的對象實例都共同具有的屬性和操作一次性地在一般類中進行顯式的定義,在特殊類中不再重復地定義一般類中已經定義的東西,但是在語義上,特殊類卻自動地、隱含地擁有它的一般類(以及所有更上層的一般類)中定義的屬性和操作。
特殊類的對象擁有其一般類的全部或部分屬性與方法,稱作特殊類對一般類的繼承。
繼承所表達的就是一種對象之間的相交關系,它使得某類對象可以繼承另外一類對象的數據成員和成員方法。
若類 B 繼承類 A 時,則屬于 B 的對象便具有類 A 的全部或部分性質(數據屬性)和功能(操作)。
我們稱被繼承的類 A 為基類、父類或超類,而稱繼承類 B 為 A 的派生類或子類。
繼承避免了對一般類和特殊類之間共同特征進行的重復描述。
2 繼承的特征
繼承關系是傳遞的。繼承是在一些比較一般的類的基礎上構造、建立和擴充新類的最有效的手段。
繼承簡化了人們對事物的認識和描述,能清晰體現相關類間的層次結構關系。
提供軟件復用功能。
通過增強一致性來減少模塊間的接口和界面,大大增加程序的易維護性。
提供多重繼承機制。從理論上說,一個類可以是多個一般類的特殊類,它可以從多個一般類中繼承屬性和方法,這便是多重繼承。而 Java 出于安全性和可靠性的考慮,僅支持單重繼承,而通過使用接口機制來實現多重繼承。
3 Java 用 extends 指明繼承關系
在 Java 程序設計中,繼承是通過 extends 關鍵字來實現的。
在定義類時使用 extends 關鍵字指明新定義類的父類,新定義的類稱為指定父類的子類,這樣就在兩個類之間建立起了繼承關系。
這個新定義的子類可以從父類那里繼承所有非 private 的屬性和方法作為自己的成員。
實際上,在定義一個類而不給出 extends 關鍵字及父類名時,默認這個類是系統類 Object 的子類。
3.1 數據成員的繼承
子類可以繼承父類的所有非私有的數據成員。
3.2 數據成員的隱藏
數據成員的隱藏是指在子類中重新定義一個與父類中已經定義的數據成員名完全相同的數據成員,即子類擁有了兩個相同名字的數據成員,一個是繼承父類的,另一個是自己定義的。
當子類引用這個同名的數據成員時,默認操作是它自己定義的數據成員,而把從父類那里繼承來的數據成員“隱藏”起來。
當子類要引用繼承自父類的同名數據成員時,可使用關鍵字 super 引導。
3.3 成員方法的繼承
子類可以繼承父類的非私有成員方法。
3.4 成員方法的覆蓋(Overload)
子類可以重新定義與父類同名的成員方法,實現對父類方法的覆蓋。
方法的覆蓋與數據成員的隱藏的不同之處在于:
子類隱藏父類的數據成員只是使之不可見,父類同名的數據成員在子類對象中仍然占有自己獨立的內存空間;
子類方法對父類同名方法的覆蓋將清除父類方法占用的內存,從而使父類方法在子類對象中不復存在。
需要注意的是:子類在重新定義父類已有的方法時,應保持與父類完全相同的方法名、返回值類型和參數列表,否則就不是方法的覆蓋,而是子類定義自己特有的方法,與父類的方法無關。
4 this 與 super
4.1 this 的使用場合
在方法內借助 this 來明確表示引用的是類的數據成員,而不是形參或局部變量,從而提高程序的可讀性。
簡單地說,this 代表了當前對象的一個引用,可將其理解為對象的另一個名字,通過這個名字可以順利地訪問對象、修改對象的數據成員、調用對象的方法。
this 的使用場合主要有以下三種:
用來訪問當前對象的數據成員:
this.數據成員
用來訪問當前對象的成員方法:
this.成員方法(參數)
當有重載的構造方法時,用來引用同類的其他構造方法:
this(參數)
4.2 super 的使用場合
super 表示的是當前對象的直接父類對象,是當前對象的直接父類對象的引用。
所謂直接父類是相對于當前對象的其他“祖先”類而言。
若子類的數據成員或成員方法名與父類的數據成員或成員方法名相同時,當要調用父類的同名方法或使用父類的同名數據成員,則可用關鍵字 super 來指明父類的數據成員和方法。
super 的使用場合有三種:
用來訪問直接父類隱藏的數據成員:
super.數據成員
用來調用直接父類中被覆蓋的成員方法:
super.成員方法(參數)
用來調用直接父類的構造方法:
super(參數)
5 構造方法的重載與繼承
5.1 構造方法的重載
一個類的若干個構造方法之間可以相互調用。
當一個構造方法需要調用另一個構造方法時,可以使用關鍵字 this,同時這個調用語句應該是整個構造方法的第一個可執行語句。
使用關鍵字 this 來調用同類的其他構造函數時,優點同樣是可以最大限度地提高對已有代碼的利用程度,提高程序的抽象度和封裝性,減少程序的維護工作量。
5.2 構造方法的繼承
子類可以繼承父類的構造方法,構造方法的繼承遵循以下的原則:
子類無條件地繼承父類的不含參數的構造方法。
如果子類自己沒有構造方法,則它將繼承父類的無參數構造方法作為自己的構造方法;如果子類自己定義了構造方法,則在創建新對象時,它將先執行繼承自父類的無參數構造方法,然后再執行自己的構造方法。
對于父類含參數的構造方法,子類可以通過在自己的構造方法中使用 super 關鍵字來調用它,但這個調用語句必須是子類構造方法的第一個可執行語句。
6 向方法傳遞對象
傳遞給方法的參數可以是表達式(如常量、變量)、對象等。
傳遞給方法的參數若是變量,則只能由實參傳遞給形參,而不能由形參帶回,它是一種單向值傳遞。
在方法的引用過程中,對于形參變量值的修改并不影響實參變量的值。
但是,傳遞給方法的參數若是對象,則方法可以對其做永久性修改。
7 類轉換
類轉換就是指父類對象與子類對象之間在一定條件下的相互轉換。
父類對象與子類對象之間相互轉換規則如下:
父類對象與子類對象之間可以隱式轉換(也稱默認轉換),也可以顯式轉換(也稱強制轉換)。
處于相同類層次的類的對象不能進行轉換。
子類對象可以轉換成父類對象,但對數據成員的引用必須使用強制轉換。
類轉換格式如下:
(子類)父類
或
(父類)子類
8 繼承與封裝的關系
在面向對象系統中,封裝性主要指的是對象的封裝性,即將屬于某一類的一個具體對象封裝起來,使其數據和操作成為一個整體。
在引入了繼承機制的面向對象系統中,對象依然是封裝得很好的實體,其他對象與它進行通訊的途徑仍然只有一條,那就是發送消息。
類機制是一種靜態機制,不管是基類還是派生類,對于對象來說,它仍然是一個類的實例,既可能是基類的實例,也可能是派生類的實例。
因此,繼承機制的引入絲毫沒有影響對象的封裝性。
繼承和封裝機制還具有一定的相似性,它們都是一種共享代碼的手段。
繼承是一種靜態共享代碼的手段,通過派生類對象的創建,可以接收某一消息,啟動其基類所定義的代碼段,從而使基類和派生類共享了這一段代碼。
封裝機制所提供的是一種動態共享代碼的手段,通過封裝,我們可將一段代碼定義在一個類中,在另一個類所定義的操作中,我們可以通過創建該類的實例,并向它發送消息而啟動這一段代碼,同樣也達到共享的目的。