菜雞的Java課筆記 第十九 繼承
繼承性的主要目的,繼承的實現,繼承的限制
繼承是面向物件中的第二大主要特點,其核心的本質在於:可以將父類的功能一直沿用下去
為什麼需要繼承?
那麼為了更好的區分出之前學習的概念與現在程式的區別,下面通過兩個具體的程式碼來進行研究
例如:現在有倆個類:Person,Student,按照原始的方式,程式程式碼實現如下:
class Person{ private String name; private int age; public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public String getName(){ return this.name; } public int getAge(){ return this.age; } } class Student{ private String name; private int age; private String school; public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public void setSchool(String school){ this.school = school; }public String getName(){ return this.name; } public int getAge(){ return this.age; } public String getSchool(){ return this.school; } } public class inherit{ public static void main(String args[]){ System.out.println(); } }
兩個類出現有重複,而且最為關鍵的問題是學生從現實的角度來看一定是個人
那麼按照這樣的理解就可以發現出現重複的核心問題所在了,就是兩個類之間沒有聯絡
之前所編寫的程式碼或者說之前所學習到的概念那麼還不足以解決多個類之間的程式碼重複消除問題
Student 是比 Person 更加細化的定義範疇
使用繼承解決問題
在java中可以利用繼承的概念來實現父類程式碼的重用問題,程式中可以使用extennds 關鍵字實現繼承操作的定義
其使用的語法如下:
class 子類 extends 父類{}
需要注意點名詞概念:
子類:也被稱為派生類
extends雖然從本質上來講屬於繼承概念,但是其翻譯為擴充套件,擴充的意思
父類 本質上在java中稱為超類(Super Class)
範例:繼承的基本使用
class Person{ private String name; private int age; public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public String getName(){ return this.name; } public int getAge(){ return this.age; } } class Student extends Person{ // Student 是Person 的子類 // 此時並沒有在Student類裡面定義任何的操作 } public class inherit{ public static void main(String args[]){ Student stu = new Student();// 例項化子類物件 stu.setName("少爺");//通過Person類繼承而來 stu.setAge(20);//通過Person類繼承而來 System.out.println("姓名:"+stu.getName+",年齡:"+stu.getAge()); } } /* 結果 姓名:少爺,年齡:20 */
通過以上的程式就可以發現一點:子類在繼承了父類之中,那麼對於父類的支援方法不會減少
但是子類可以進一步擴充屬於自己的屬性與方法
範例:繼承的基本使用
class Person{ private String name; private int age; public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public String getName(){ return this.name; } public int getAge(){ return this.age; } } class Student extends Person{ // Student 是Person 的子類 private String school; // 子類自己擴充的屬性 public void setSchool(String school){ this.school = school; } public String getSchool(){ return this.school; } public class inherit{ public static void main(String args[]){ Student stu = new Student();// 例項化子類物件 stu.setName("少爺");//通過Person類繼承而來 stu.setAge(20);//通過Person類繼承而來 stu.setSchool("清華");//子類自己擴充的屬性 System.out.println("姓名:"+stu.getName+",年齡:"+stu.getAge()+",學校:"+stu.getSchool()); } } /* 結果 姓名:少爺,年齡:20,學校:五道口 */
通過這樣的繼承實現發現:
父類的功能可以延續到子類繼續使用,這樣在某些父類不能夠修改的情況下,就可以通過繼承來實現功能的擴充
子類中至少可以維持父類的原始方法不變,也就是說在子類裡面父類的方法功能不會減少
*/
/* 繼承的使用限制
雖然繼承的核心目的在於擴充類中的已有功能,但是在實際的開發之中,繼承的使用也是存在有諾幹限制的,這些限制必須注意
限制一:java不允許多重繼承,也就是說一個子類只能夠繼承一個父類
因為C++它支援多繼承,也就是說一個子類可以同時繼承多個父類
範例:錯誤程式碼
class A{ } class B{ } class C extendsa A,B{ } public class inherit{ public static void main(String args[]){ System.out.println(); } }
那麼為什麼實際中會出現這種程式碼呢?
其實本質上也只是希望C類可以同時繼承A,B類的方法,但是由於這樣的做法與現實生活有衝突,所以從java的角度就遮蔽了,但是有解決方案
雖然java不允許多重繼承,但是卻允許多層繼承,以下程式碼為方案:
class A{ } class Bextendsa A{ } class C extendsa B{ } public class inherit{ public static void main(String args[]){ System.out.println(); } }
此時的C類實際上就具備有A,B類的全部定義,但是從實際的開發,這種繼承的層次關係不要超過三層
限制二:子類在繼承父類之後會將父類中的全部結構繼承下來,但是對於私有的操作屬於隱式繼承(子類不能直接呼叫),而所有的非私有操作屬於顯式繼承(可以直接呼叫)
範例:觀察顯式繼承
class A{ private String name: public void setName(String name){ this.name = name; } public String getName(){ return this.name; } } class B extendsa A{ } public class inherit{ public static void main(String args[]){ B b= new B(); b.setName("少爺"); System.out.println(b.getName()); } }
現在對於子類B而言是存在name屬性的,但是這個屬性子類並不能夠直接操作
範例:子類B直接訪問
class A{ private String name: public void setName(String name){ this.name = name; } public String getName(){ return this.name; } } class B extendsa A{ public void print(){ System.out.println(name); } } public class inherit{ public static void main(String args[]){ B b= new B(); b.setName("少爺"); System.out.println(b.getName()); } }//結果程式出錯
也就是說此時的name屬於隱式繼承,而所有的setter方法屬於顯式繼承,顯式繼承可以直接呼叫,而隱式繼承的只能夠間接的操作或者不能夠操作
限制三:在例項化子類物件時會預設呼叫子類的無參構造方法,但是在執行子類構造前會首先自動例項化父類構造為父類的物件例項化,也就是說父類物件永遠早於子類物件的例項化
範例:觀察例項化過程
class A{ public A(){ System.out.println("***********************"); } } class B extends A{ public B(){ System.out.println("###########################"); } } public class inherit{ public static void main(String args[]){ B b= new B(); } } /* 結果: *********************** ########################### */
如果說現在非要為子類加上一個呼叫父類構造的標記,那麼就可以使用“super()”的形式完成
class A{ public A(){ System.out.println("***********************"); } } class B extends A{ public B(){ super(); // 表示由子類構造呼叫父類構造 System.out.println("###########################"); } } public class inherit{ public static void main(String args[]){ B b= new B(); } } /* 結果: *********************** ########################### */
也就是證明,在子類的構造之中其實一直隱藏了一行“super()”語句,但是在進行無參父類構造呼叫的時候,寫上“super()”是沒有意義的
往往是在父類沒有提供無參構造時使用的
範例:錯誤程式碼
class A{ public A(String name){ System.out.println("***********************"); } } class B extends A{ public B(){ // super(); // 表示由子類構造呼叫父類構造 System.out.println("###########################"); } } public class inherit{ public static void main(String args[]){ B b= new B(); } }//結果程式出錯
這個時候很明顯使用隱含的“super()”並不合適,所以應該明確的呼叫指定引數的構造方法
class A{ public A(String name){ System.out.println("***********************"); } } class B extends A{ public B(String name){ super(name); // 表示由子類構造呼叫父類構造 System.out.println("###########################"); } } public class inherit{ public static void main(String args[]){ B b= new B("少爺"); } }
在大多數情況下父類一般都會提供有無參構造方法,這個時候可以在子類構造中不出現“super()”的語句
但是如果此時父類沒有提供無參構造方法,那麼子類就必須使用“super()”呼叫指定引數的構造方法
對於 super 呼叫構造方法的情況需要注意如下幾項:
不管你子類怎麼折騰都一定要去呼叫父類的構造方法,即:呼叫父類構造使用 super()
super() 是在子類中編寫的,表示通過子類的構造方法去呼叫父類構造,必須放在子類構造方法的首行,不能與“this()”不能同時出現在構造方法之中,兩者關係屬於二選一
如果現在父類中沒有提供無參構造方法,那麼在子類構造之中必須明確的呼叫有參構造方法,必須使用 super 呼叫指定引數的父類構造
this 是應用在本類的關鍵字,而 super 是應用在子類中的關鍵字,利用 super 找到父類結構
分析:關於this()與super()的問題
在之前學習過this()表示呼叫本類的其他構造方法,而現在有了繼承關係之後,可以使用super() 由子類呼叫父類中指定的構造方法,並且這兩個語句都一定要出現在首行,也就是說這兩個語句不能同時出現
範例:不讓子類呼叫父類的構造
class A{ public A(String name){ System.out.println("***********************"); } } class B extends A{ public B(){ } public B(String name){ this();// System.out.println("###########################"); } } public class inherit{ public static void main(String args[]){ B b= new B("少爺"); } }
在子類的構造方法中出現了“this()”,這樣就不會出現“super()”的預設執行而轉為呼叫本類的構造方法了
那麼這樣是不是可以不呼叫父類構造了呢?
總結
1.繼承的唯一好處就是進行了功能的擴充,並且java只支援單繼承侷限
2.子類物件例項化時一定要先例項化父類物件,而後在例項化子類自己的物件
*/