在《Think in Java》中有這樣一句話:復用程式碼是Java眾多引人注目的功能之一。但要成為極具革命性的語言,僅僅能夠複製程式碼並對加以改變是不夠的,它還必須能夠做更多的事情。在這句話中最引人注目的是「複用程式碼」,盡可能的複用程式碼使我們程式設計師一直在追求的,現在我來介紹一種複用程式碼的方式,也是java三大特性之一---繼承。
繼承
在解釋前我們先來看一個例子,而此例子是前篇博文(並提高篇-----理解java的三大特性之封裝)的。
從這裡我們可以看出,Wife、Husband兩個類除了各自的husband、wife外其餘部分全部相同,作為一個想最大限度實現復用代碼的我們是不能夠忍受這樣的重複代碼,如果再來一個小三、小四、小五……(扯遠了)我們是不是也要這樣寫呢?那我們要如何來實作這些類別的可重複使用呢?利用繼承! !
首先我們先離開軟體程式設計的世界,從常識中我們知道丈夫、妻子、小三、小四…,他們都是人,而且都有一些共通點,有名字、年齡、性別、頭等等,而且他們都能夠吃東西、走路、說話等等共同的行為,所以從這裡我們可以發現他們都擁有人的屬性和行為,同時也是從人那裡繼承來的這些屬性和行為的。
從上面我們基本上了解了繼承的概念了,繼承是使用已存在的類別的定義作為基礎建立新類別的技術,新類別的定義可以增加新的資料或新的功能,也可以用父類別的功能,但不能選擇性地繼承父類別。透過使用繼承我們能夠非常方便地複用以前的程式碼,能夠大大的提高開發的效率。
對於Wife、Husband使用繼承後,除了代碼量的減少我們還能夠非常明顯的看到他們的關係。
繼承所描述的是“is-a”的關係,如果有兩個對象A和B,若可以描述為“A是B”,則可以表示A繼承B,其中B是被繼承者稱之為父類別或超類,A是繼承者稱為子類別或衍生類別。
實際上繼承者是被繼承者的特殊化,它除了擁有被繼承者的特質外,還擁有自己獨有特色。例如貓有抓老鼠、爬樹等其他動物沒有的特性。同時在繼承關係中,繼承者完全可以替換被繼承者,反之則不可以,例如我們可以說貓是動物,但不能說動物是貓就是這個道理,其實對於這個我們將其稱之為「向上轉型”,下面介紹。
誠然,繼承定義了類別如何相互關聯,共享特性。對於若干個相同或相識的類,我們可以抽像出他們共有的行為或屬相並將其定義成一個父類或超類,然後用這些類繼承該父類,他們不僅可以擁有父類的屬性、方法也可以定義自己獨有的屬性或方法。
同時使用繼承時需要記住三句話:
1、子類別擁有父類別非private的屬性與方法。
2、子類別可以擁有自己屬性與方法,即子類別可以將父類別擴充。
3、子類別可以用自己的方式實作父類別的方法。 (以後介紹)。
綜上所述,使用繼承確實有許多的優點,除了將所有子類別的共同屬性放入父類,實現代碼共享,避免重複外,還可以使得修改擴展繼承而來的實現比較簡單。
誠然,講到繼承一定少不了這三個東西:構造器、protected關鍵字、向上轉型。
構造者
透過前面我們知道子類別可以繼承父類別的屬性和方法,除了那些private的外還有一樣是子類別繼承不了的---建構器。對於構造器而言,它只能夠被調用,而不能被繼承。 呼叫父類別的建構方法我們使用super()即可。
對於子類別而已,其構造器的正確初始化是非常重要的,而且當且僅當只有一個方法可以保證這點:在構造器中調用父類構造器來完成初始化,而父類構造器具有執行父類別初始化所需的所有知識和能力。
public class Person { protected String name; protected int age; protected String sex; Person(){ System.out.println("Person Constrctor..."); } } public class Husband extends Person{ private Wife wife; Husband(){ System.out.println("Husband Constructor..."); } public static void main(String[] args) { Husband husband = new Husband(); } } Output: Person Constrctor... Husband Constructor...
透過這個範例可以看出,建構過程是從父類別「向外」擴散的,也就是從父類別開始向子類別一級一級地完成建構。而且我們沒有顯示的引用父類別的建構器,這就是java的聰明之處:編譯器會預設給子類別呼叫父類別的建構器。
但是,這個預設呼叫父類別的建構器是有前提的:父類別有預設建構器。如果父類別沒有預設建構器,我們就要必須顯示的使用super()來呼叫父類別建構器,否則編譯器會報錯:無法找到符合父類別形式的建構器。
public class Person { protected String name; protected int age; protected String sex; Person(String name){ System.out.println("Person Constrctor-----" + name); } } public class Husband extends Person{ private Wife wife; Husband(){ super("chenssy"); System.out.println("Husband Constructor..."); } public static void main(String[] args) { Husband husband = new Husband(); } } Output: Person Constrctor-----chenssy Husband Constructor...
所以綜上所述:對於繼承而已,子類別會預設呼叫父類別的建構器,但是如果沒有預設的父類別建構器,子類別必須要顯示的指定父類別的建構器,而且必須是在子類別構造器中做的第一件事(第一行程式碼)。
protected關鍵字
private存取修飾符,以封裝而言,是最好的選擇,但這個只是基於理想的世界,有時候我們需要這樣的需求:我們需要盡可能將某些事物對這個世界隱藏,但是仍然允許子類別的成員來存取它們。這時候就需要使用到protected。
對於protected而言,它指明就類用戶而言,他是private,但是對於任何繼承與此類的子類而言或者其他任何位於同一個包的類而言,他卻是可以訪問的。
public class Person { private String name; private int age; private String sex; protected String getName() { return name; } protected void setName(String name) { this.name = name; } public String toString(){ return "this name is " + name; } /** 省略其他setter、getter方法 **/ } public class Husband extends Person{ private Wife wife; public String toString(){ setName("chenssy"); //调用父类的setName(); return super.toString(); //调用父类的toString()方法 } public static void main(String[] args) { Husband husband = new Husband(); System.out.println(husband.toString()); } } Output: this name is chenssy
從上面範例可以看書子類別Husband可以明顯地呼叫父類別Person的setName()。
誠然儘管可以使用protected存取修飾符來限制父類別屬性和方法的存取權限,但是最好的方式還是將屬性保持為private(我們應一致保留更改底層實現),透過protected方法來控制類別的繼承者的存取權限。
上轉型
在上面的繼承中我們談到繼承是is-a的相互關係,貓繼承與動物,所以我們可以說貓是動物,或者說貓是動物的一種。這樣將貓看做動物就是向上轉型。如下:
public class Person { public void display(){ System.out.println("Play Person..."); } static void display(Person person){ person.display(); } } public class Husband extends Person{ public static void main(String[] args) { Husband husband = new Husband(); Person.display(husband); //向上转型 } }
在這我們通過Person.display(husband)。這句話可以看出husband是person類型。
將子類別轉換成父類,在繼承關係上面是向上移動的,所以一般稱為向上轉型。由於向上轉型是從一個叫專用類型轉換到較通用類型轉換,所以它總是安全的,唯一改變的可能是屬性和方法的遺失。這就是為什麼編譯器在「未曾明確表示轉型」活「未曾指定特殊標記」的情況下,仍然允許向上轉型的原因。
謹慎繼承
上面講了繼承所帶來的諸多好處,那我們是不是就可以大肆地使用繼承?送你一句話:慎用繼承。
首先我們需要先明確,繼承有下列缺陷:
1、父類變,且子類別必須改變。
2、繼承破壞了封裝,而對於父類別而言,它的實作細節對與子類別來說都是透明的。
3、繼承是強耦合關係。
所以說當我們使用繼承的時候,我們需要確信使用繼承確實是有效可行的辦法。那麼到底要不要使用繼承呢? 《Think in java》中提供了解決方法:問問自己是否需要從子類別轉向父類別向上轉型。如果必須向上轉型,繼承是必要的,但是如果不需要,則應好好考慮自己是否需要繼承。
慎用繼承! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
以上就是 java提高篇(二)-----理解java的三大特性之繼承的內容,更多相關內容請關注PHP中文網(www.php.cn)!