繼承(Inheritance)、多型(Polymorphism)

8.1 繼承

您可以基於某個父類別對物件的定義加以擴充,而制訂出一個新的子類別定義,子類別可以繼承父類別原來的某些定義,並也可能增加原來的父類別所沒有的定義,或者是重新定義父類別中的某些特性,事實上,在您開始學會使用 "class" 關鍵字定義類別的同時,您也已經使用了繼承的功能,因為在 Java 中,所有的類別都直接或間接的繼承了 java.lang.Object 類別。

8.1.1 擴充(extends)父類別

假設您先前已經為您的動物園遊戲撰寫了一些 Bird 相關類別,現在想要將之擴充,讓動物園擁有像是雞、麻雀等更多鳥的種類,那麼您可以擴充 Bird 類別,這麼一來許多 Bird 中所使用的功能都可以留下來,並基於它擴充一些新的 Chicken、Sparrow 類別,您不用重寫所有的功能,您可以「擴充」(extends)原先已定義好的類別再增加新的定義。

Java 中使用 "extends" 作為其擴充父類別的關鍵字,其實就相當於一般所常稱的「繼承」(Inherit),以動物園中最鳥類為例,假設您原先已定義好一個 Bird 類別,如範例 8.1 所示。 範例 8.1 Bird.java

public class Bird { private String name;

public Bird() {
}

public Bird(String name) {
    this.name = name;
}

public void walk() {
    System.out.println("走路");
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

}

您可以繼承 Bird 並將之擴充為 Chicken 類別,在擴充(繼承)的關係中,被擴充的類別為「父類別」(Parent class)或「基礎類別」(Base class),而擴充父類別的類別就稱之為「子類別」(Child class)或「衍生類別」(Derived class),父類別跟子類別之間,有「is a」的關係,例如雞「是一種」鳥(Chicken is a bird)。在 Java 中要擴充類別定義時,您要使用 "extends" 關鍵字,並指定要被擴充的類別,如範例 8.2 所示。 範例 8.2 Chicken.java

public class Chicken extends Bird { // 擴充Bird類別 private String crest; // 新增私有成員,雞冠描述

public Chicken() {
    super();
}

// 定義建構方法
public Chicken(String name, String crest) {
    super(name);
    this.crest = crest;
}

// 新增方法
public void setCrest(String crest) {
    this.crest = crest;
}

public String getCrest() {
    return crest;
}

public void wu() {
   System.out.println("咕咕叫…");
}

}

當您擴充某個類別時,該類別的所有 "public" 成員都可以在衍生類別中被呼叫使用,而 "private" 成員則不可以直接在衍生類別中被呼叫使用;在這個例子中,Bird 類別中已經有 name 成員,您讓 Chicken 擴充 Bird 並新增了 crest 成員,而方法上您新增 "public" 的 getCrest() 等方法,而 getName() 與 walk() 等方法則直接繼承父類別中已定義的內容。

在擴充某個類別之後,您可以一併初始父類別的建構方法,以完成相對應的初始動作,這可以使用 super() 方法來達到,它表示呼叫基底類別的建構方法,super() 必須在建構方法一開始就呼叫,在子類別的建構方法中,如果不用 super() 指定使用父類別中的哪個建構方法來初始,則預設會呼叫父類別中無參數的建構方法。

父類別的 "public" 成員可以直接在衍生類別中使用,而 "private" 成員則不行,"private" 類別只限於定義它的類別之內來存取,如果您想要與父類別的 "private" 成員溝通,就只能透過父類別中繼承下來的 "public" 方法成員,例如範例中的 getName() 方法。

8.1.2 被保護的(protected)成員

在之前的範例中,資料成員都預設為 "private" 成員,也就是私用成員,私用成員只能在物件內部使用,不能直接透過參考名稱加上 "." 呼叫使用,即使是擴充了該類別的衍生類別也無法直接使用父類別的私用成員,您只能透過父類別所提供的 "public" 方法成員來呼叫或設定私用成員。

然而有些時候,您希望擴充了基底類別的衍生類別,也能夠直接存取基底類別中的成員,而不是透過 "public" 方法成員,但也不是將資料成員宣告為 "public",因為您只想這些成員被子類別物件所使用,而不希望這些成員被其它外部物件直接呼叫使用。

您可以宣告這些成員為「被保護的」(protected)成員,保護的意思表示存取該成員是有條件限制的,當您將類別的成員宣告為受保護的成員之後,繼承的類別就可以直接使用這些成員,但這些成員仍然受到保護,不同套件(package)的物件不可直接呼叫使用 protected 成員

8.1.3 重新定義(Override)方法

類別是物件的定義書,如果父類別中的定義並不符合您的需求,可以在擴充類別的同時重新定義,您可以重新定義方法的實作內容、成員的存取權限,或是成員的返回值型態(重新定義返回值型態是 J2SE 5.0 新功能)。

舉個例子來說,看看下面這個類別:

public class SimpleArray { protected int[] array;

public SimpleArray(int i) {
    array = new int[i];
}
public void setElement(int i, int data) {
    array[i] = data;
}
....

}

這個類別設計一個簡單的陣列工具類別,不過您覺得它的 setElement() 方法不夠安全,您希望增加一些陣列的長度檢查動作,於是您擴充該類別並重新定義 setElement() 方法:

public class SafeArray extends SimpleArray { public SafeArray(int i) { super(i); } // 重新定義setElement() public void setElement(int i, int data) { if(i < array.length) super.setElement(i, data); } .... }

這麼一來,以 SafeArray 類別的定義所產生的物件,就可以使用新的定義方法,就 SafeArray 類別來說,由於操作介面與 SimpleArray 是一致的,所以您可以這麼使用:

SimpleArray simpleArray = new SafeArray(); simpleArray.setElement();

results matching ""

    No results matching ""