前言
社會中就有繼承的概念(百度百科):繼承是指一個對象直接使用另一對象的屬性和方法。也指按照法律或遵照遺囑接受死者的財產、職務、頭銜、地位等。這個解釋中的前一句正說明了我們要今天要講的對象(繼承)的大體特性。
在寫Java時用到繼承的情況有?
當我們準備編寫一個類時,發現某個類已有我們所需要的成員變量和方法,假如我們想復用這個類的成員變量和方法,即在所編寫類中不用聲明成員變量就相當於有了這個成員變量,不用定義方法就相當於有了這個方法,那麼我們可以將編寫的類聲明為這個類的子類即繼承。
小知識:
源類,基類,超類或者父類都是一個概念
導出類,繼承類,子類也都是同一個概念
繼承的語法
在類聲明中,使用關鍵字extends來聲明一個類的子類:
class 子類名 extends 父類名 { …}注意:如類聲明語句中沒有extends子句,則該類為java.lang包中的Object的子類。這就說明了java中的代碼其實都有一個繼承的關係,只不過是繼承Object這個java中最根本的父類。
繼承的特點
子類擁有父類非private的屬性和方法,子類繼承的父類方法和成員變量可以當作自己的方法和成員變量一樣被子類的實例方法使用。
子類可以有自己屬性和方法,即子類可以在父類的基礎上對父類進行擴展。
子類可以用自己的方式實現父類的方法。(重寫或者覆蓋)
訪問權限和繼承之間的關係
訪問限制修飾符限制對象對成員變量操作和方法調用,也限制繼承性
構造器對繼承的影響
什麼是構造器:
構造器的特性:
與一般方法名不同的是,構造方法名必須和類名保持一致,並且沒有返回值。
Java編譯器會自動創建無參構造函數,因此在類中,無參構造即使沒有,我們也可省略不寫。實例化對象時無需賦值。
倘若類中已存在有參構造函數,則編譯器不再提供默認無參構造。實例化對象時需賦值,不然報錯。
當類實例化一個對象時會自動調用構造方法。
構造器在Java的繼承中會產生什麼影響呢?
我們雖然繼承了父類但是父類的構造器是我們子類繼承不了的,我們只能去調用父類的構造器。
那麼在繼承並且編寫子類的構造方法的時候就要注意兩種情況了:
父類使用默認構造器
package Extends; public class Father { Father(){ System.out.println("This is Father Constrctor"); }}package Extends; public class Nosuper extends Father{ Nosuper(){ System.out.println("This is Nosuper Constrctor"); } public static void main(String[] args) { Nosuper no=new Nosuper(); } }OUTPUT:This is Father ConstrctorThis is Nosuper Constrctor父類不使用默認構造器
package Extends; public class Father { Father(String name){ System.out.println("This is Father Constrctor,name is "+name); }}package Extends; public class Nosuper extends Father{ Nosuper(){ super("YYH"); System.out.println("This is Nosuper Constrctor"); } public static void main(String[] args) { Nosuper no=new Nosuper(); }}OUTPUT:This is Father Constrctor,name is YYHThis is Nosuper Constrctor總結:對於繼承來說,子類會默認調用父類的構造器,但是如果沒有默認的父類構造器,子類必須要調用父類的構造器,而且必須是在子類構造器中做的第一件事(第一行代碼)。
繼承中的向上轉型
當超類對象引用變量引用子類對象時,被引用對象的類型而不是引用變量的類型決定了調用誰的成員方法,但是這個被調用的方法必須是在超類中定義過的,也就是說被子類覆蓋的方法,但是它仍然要根據繼承鏈中方法調用的優先級來確認方法,該優先級為:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
package _4_8; class A { public String show(D obj) { return ("A and D"); } public String show(A obj) { return ("A and A"); } } class B extends A{ public String show(B obj){ return ("B and B"); } public String show(A obj){ return ("B and A"); } } class C extends B{}class D extends B{}public class t { public static void main(String[] args) { A a1 = new A(); A a2 = new B(); B b = new B(); C c = new C(); D d = new D(); System.out.println("1--" + a1.show(b)); System.out.println("2--" + a1.show(c)); System.out.println("3--" + a1.show(d)); System.out.println("---"); System.out.println("4--" + a2.show(b)); System.out.println("5--" + a2.show(c)); System.out.println("6--" + a2.show(d)); System.out.println("6--" + a2.show(a1)); System.out.println("*"); System.out.println("7--" + b.show(b)); System.out.println("8--" + b.show(c)); System.out.println("9--" + b.show(d)); }}OUTPUT:1--A and A2--A and A3--A and D---4--B and A5--B and A6--A and D6--B and A*7--B and B8--B and B9--A and D仔細理解一下其中的代碼不難理解其中向上轉型在繼承中的作用。
按照this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)這個順序一步一步的執行就會得到結果。
將子類轉換成父類,在繼承關係上面是向上移動的,所以一般稱之為向上轉型。由於向上轉型是從一個叫專用類型向較通用類型轉換,所以它總是安全的,唯一發生變化的可能就是屬性和方法的丟失。
繼承慎用
你會感覺當你在編寫三四個程序的時候用繼承解決了他們公共的部分是很方便的,但是如果你程序很大,class很多而且都繼承於一個類中,當你想通過改變父類的一些信息來改變一個子類的信息的時候就會發現其他的子類也會隨之改變,有時候會對其他的子類產生不必要的結果。
父類變了其他的子類就會隨之全部改變。
繼承破壞了封裝,對於父類而言,它的實現細節對與子類來說都是透明的。
繼承是一種強耦合關係。
「問一問自己是否需要從子類向父類進行向上轉型。如果必須向上轉型,則繼承是必要的,但是如果不需要,則應當好好考慮自己是否需要繼承」