Java核心知識之介面、繼承和多型-繼承講解
一、類的繼承
繼承在面向物件開發思想中是一個非常重要的概念,它使整個程式架構具有一定的彈性,在程式中複用一些已經定義完善的類不僅可以減少軟體開發週期,也可以提高軟體的可維護性和可擴充套件性。
繼承的基本思想是基於某個父類的擴充套件,指定出一個新的子類,子類可以繼承父類原有的屬性和方法,也可以增加父類所不具備的屬性和方法,或者直接重寫父類中的某些方法。例如:平行四邊形是特殊的四邊形,可以說平行四邊形類繼承了四邊形,這時平行四邊形類將所有四邊形具有的屬性和方法都保留下來,並基於四邊形類擴充套件了一些新的平行四邊形特有的屬性和方法。
eg :分別建立 Test1 類和 Test2 類,在 Test1 類中編寫成員方法 doSomething() 和 doIt() ,使 Test2 類繼承 Test1 類,重寫父類的這兩個方法和構造方法,並新增 doSomethingnew() 方法。其他 Test2 類的構造方法中使用 super 關鍵字呼叫父類的構造方法和成員方法等。
class Test1 {
public Test1(){ //構造方法
System.out.println("Test1.Test1()");
}
protected void doSomething() { //成員方法
System.out.println("Test1.doSomething()");
}
protected Test1 doIt() { //方法返回值型別為 Test1 型別
System.out.println("Test1.doIt()");
return new Test1();
}
}
class Test2 extends Test1{ //繼承父類
public Test2 () { //構造方法
super(); //呼叫父類的構造方法
super.doSomething(); //呼叫父類成員方法
System.out.println("Test2.Test2()");
}
public void doSomethingnew() { //新增方法
System.out.println("Test2.doSomethingnew()");
}
public void doSomething() { //重寫父類方法
System.out.println("Test2.doSomething()");
}
public Test2 doIt() { //重寫父類方法,方法返回值型別為 Test2 型別
System.out.println("Test2.doIt()");
return new Test2();
}
}
定義了兩個類,其他 Test2 類繼承 Test1 類,可以說 Test1 類為 Test2 類的父類, Test2 類為 Test1 類的子類。在子類中可以連通初始化父類構造方法來完成子類初始化操作,既可以在子類的構造方法中使用 super() 語句呼叫父類的構造方法,也可以在子類中使用 super 關鍵字呼叫父類的成員方法等,但是子類沒有許可權呼叫父類中被修飾為 private 的方法,只可以呼叫父類中修飾為 public 或 protected 的成員方法,例如,子類構造方法中可以使用 super 關鍵字呼叫父類的 doSomething 方法,因為 doSomething() 方法的許可權修飾符為 protected 。 同時在子類中也可以定義一些新方法,如子類中的 doSomethingnew() 方法。
繼承並不只是擴充套件父類的功能,還可以重寫父類的成員方法。重寫(換可以稱為覆蓋)就是在子類中將父類的成員方法的名稱保留,重寫成員方法的實現內容,更改成員方法的儲存許可權,或是修改成員方法的返回值型別。例如,子類中的 doSomething|() 方法,除了重寫方法的實現內容之外,還將方法的修飾許可權修改為 public 。
在繼承中還有一種特殊的重寫方式,子類與父類的成員方法返回值、方法名稱、引數型別即個數完全相同,唯一不同的是方法實現內容,這種特殊重寫方式被稱為重構。
當重寫父類方法時,修改方法的修飾許可權只能從小的範圍到大的範圍改變,例如父類中的 doSomethin() 方法的修飾許可權為 protected ,繼承後子類中的方法 doSomething() 的修飾許可權只能修改為 public ,不能修改為 private 。
在 Java 中一切都以物件的形式處理,在繼承的機制中,建立一個子類物件,將包含一個父類子物件,這個物件與父類建立的物件一樣。兩者的區別在與後者來自外部,而前者來自子類物件的內部。當例項化子類物件時,父類物件也相應被例項化,換句話說,在例項化子類物件時,Java 編輯器會在子類的構造方法中自動呼叫父類的無參構造方法。
eg :建立 Subroutine 類和兩個父類,分別為 Parent 和 SubParent 。這 3 個類的繼承關係是 Subroutine 類繼承 SubParent 類,而 SubParent 類繼承 Parent 類。分別在這 3 個類的構造方法中輸出構造方法名稱,然後建立 Subroutine 類的例項物件,繼承機制將使該類的父類物件自動初始化。
class Parent{//父類
public Parent() {
System.out.println("呼叫父類的 parent() 構造方法");
}
}
class SubParent extends Parent{ //繼承 Parent 類
public SubParent() {
System.out.println("呼叫子類的 SubParent() 構造方法");
}
}
public class Subroutine extends SubParent{ //繼承 SubParent 類
public Subroutine() {
System.out.println("呼叫子類的 Subroutine()構造方法");
}
public static void main(String[] args) {
Subroutine s=new Subroutine(); //例項化子類物件
}
}
執行結果為 :
呼叫父類的 parent() 構造方法
呼叫子類的 SubParent() 構造方法
呼叫子類的 Subroutine()構造方法
在子類 Subroutine 的主方法中只調用子類的構造方法例項化子類物件,並且在子類構造方法中沒有呼叫父類構造方法的任何語句,但是在例項化子類物件時它相應太哦用了父類的構造方法。在結果中可以看到呼叫構造方法的順序,首先是頂級父類,然後使上一級父類,最後是子類。也就是說例項化子類物件時首先要例項化父類物件,然後再例項化子類物件,所以在子類構造方法訪問父類的構造方法之前,父類已經完成例項化操作。
在例項化子類物件時,父類無參構造方法將被自動呼叫,但由參構造方法並不能被自動呼叫,只能依賴於 super 關鍵字顯式地呼叫父類的構造方法。
如果使用 finalize() 方法對物件進行清理,需要確保子類的 finalize() 方法的最後一個動作是呼叫父類的 finalize() 方法,以保證當垃圾回收物件佔用記憶體時,物件的所有部分都能被正常終止。