天天看點

再談 Java 的繼承和超類 Object(1)

再談 Java 的繼承和超類 Object(1)

01、

利用繼承,我們可以基于已存在的類構造一個新類。繼承的好處在于,子類可以複用父類的非 private 的方法和非 private 成員變量。

is-a 是繼承的一個明顯特征,就是說子類的對象引用類型可以是一個父類。我們可以将通用的方法和成員變量放在父類中,達到代碼複用的目的;然後将特殊的方法和成員變量放在子類中,除此之外,子類還可以覆寫父類的方法。這樣,子類也就煥發出了新的生命力。

一個對象變量可以引用多種類型的現象被稱為多态。多态發生的前提條件就是繼承。也就是說,先有繼承,後有多态。

class Wanger {
    public void write() {
        System.out.println("我為自己活着");
    }
}
class Wangxiaoer extends Wanger {
    public void write() {
        System.out.println("我也為自己活着");
    }
}
class Test {
    public static void main(String [] args) {
        Wanger wanger;
        wanger = new Wanger();
        wanger = new Wangxiaoer();
        Wangxiaoer wangxiaoer;
        //wangxiaoer = new Wanger(); // 不可以
        wangxiaoer = new Wangxiaoer(); // 隻能這樣
    }
}      

wanger 這個對象變量既可以引用 Wanger 對象,也可以引用 Wangxiaoer對象。但 wangxiaoer 就隻能引用 Wangxiaoer 對象,不能引用 Wanger 對象。根本的原因在于 Wangxiaoer 是 Wanger 的繼承者。

當使用 wanger 調用 write() 方法時,程式會在運作時自動識别其引用的對象類型,然後選擇調用哪個方法——這種現象稱為動态綁定。

動态綁定有一個非常重要的特性:無需對現有的代碼進行修改,就能對程式進行擴充。假如 Wangdaer 也繼承了 Wanger,并且 wanger 引用了Wangdaer 的對象,那麼 wanger.write() 仍然可以正常運作。

當然了,有些類不願意被繼承,也沒法被繼承。誰不願意被繼承呢?比如武則天,親手弄死自己的親兒子。誰沒法被繼承呢,每朝每代最後的那位倒黴皇帝。

類怎麼做到不被繼承呢?可以使用 final 關鍵字。final 關鍵字修飾的類不能被繼承,final 修飾的方法不能被覆寫。

final class Wanger {

   public final void write() {

       System.out.println("你們誰都别想繼承我");

   }

}

繼承是面向對象程式設計當中舉足輕重的一個概念,與多态、封裝共為面向對象的三個基本特征。 繼承可以使得子類具有父類的成員變量和方法,還可以重新定義、追加成員變量和方法等。

在設計繼承的時候,可以将通用的方法和成員變量放在父類中。但不建議随心所欲地将成員變量以 protected 的形式放在父類當中;盡管允許這樣做,并且子類可以在需要的時候直接通路,但這樣做會破壞類的封裝性(封裝要求成員變量以 private 的形式出現,并且提供對應 getter / setter 用來通路)。

Java 是不允許多繼承的,為什麼呢?

如果有兩個類共同繼承一個有特定方法的父類,那麼該方法會被兩個子類重寫。然後,如果你決定同時繼承這兩個子類,那麼在你調用該重寫方法時,編譯器不能識别你要調用哪個子類的方法。

這也正是著名的菱形問題,見下圖。ClassC 同時繼承了 ClassA 和 ClassB,ClassC 的對象在調用 ClassA 和 ClassB 中重載的方法時,就不知道該調用 ClassA 的方法,還是 ClassB 的方法。

再談 Java 的繼承和超類 Object(1)

02、

在 Java 中,所有類都由 Object 類繼承而來。Object 這個單詞的英文意思是對象,是不是突然感覺頓悟了——萬物皆對象?沒錯,Java 的設計者真是良苦用心了啊!現在,你一定明白了為什麼 Java 是面向對象程式設計語言的原因。

你可能會疑惑地反問道:“我的類明明沒有繼承 Object 類啊?”如果一個類沒用顯式地繼承某一個類,那麼它就會隐式地繼承 Object 類。換句話說,不管是雞生了蛋,還是蛋孵出了雞,總有一隻 Object 雞或者一個 Object 蛋。

在面試的時候,你可能會被問到這麼一個問題:“Object 類包含了哪些方法呢?”

1)protected Object clone() throws CloneNotSupportedException 建立并傳回此對象的副本。

不過,《阿裡巴巴 Java 開發手冊》上建議:慎用 Object 的 clone 方法來拷貝對象。因為 Object 的 clone 方法預設是淺拷貝,如果想實作深拷貝需要重寫 clone 方法實作屬性對象的拷貝。

什麼是淺拷貝,什麼是深拷貝呢?

淺拷貝是指在拷貝對象時,會對基本資料類型的變量重新複制一份,而對于引用類型的變量隻拷貝了引用,并沒有對引用指向的對象進行拷貝。

深拷貝是指在拷貝對象時,同時對引用指向的對象進行拷貝。

淺拷貝和深拷貝的差別就在于是否拷貝了對象中的引用變量所指向的對象。