理解java的三大特性之繼承
繼承是所有OOP語言不可缺少的部分,在java中使用extends關鍵字來表示繼承關系。當創建一個類時,總是在繼承,如果沒有明確指出要繼承的類,就總是隱式地從根類Object進行繼承。java語言不支持多重繼承,也就是說,子類至多只能有一個父類。
1.繼承的作用
通過繼承,子類可以使用父類中的一些成員變量和方法,從而提高代碼的重用性,提高開發效率。
2.哪些類不能被繼承
被final修飾的類不能被繼承。java中常見的不能被繼承的類有:String,StringBuffer,StringBuilder,以及基本類型的包裝類Double,Integer,Long等。
3.繼承的實現
3.1 子類可以繼承父類原有的屬性和方法,也可以增加父類所不具備的屬性和方法。
package zhishidian; class Pet {
//父類的屬性,有被private和public修飾的 private String name = "無名氏"; //昵稱 private int health = 100; //健康值 public int love = 0; //親密度 /** * 無參構造方法 */ public Pet(){ this.health = 95; System.out.println("執行寵物的無參構造方法"); } /** * 有參構造方法 * @param name 昵稱 */ public Pet(String name){ this.name = name; } public String getName(){ return name; } public int getHealth(){ return health; } public int getLove(){ return love; } /** * 輸出寵物信息 */ public void print(){ System.out.println("寵物的自白:\n我的名字叫" + this.name + ",我的健康值是" + this.health + ",我和主人的親密程度是" + this.love + "。"); } } public class Dog extends Pet { //子類可以增加父類所不具備的屬性和方法 private String strain;//品種 public String getStrain(){ return strain; } /** * 有參構造方法 * @param name 昵稱 * @param strain 品種 */ public Dog(String name, String strain){ //此處不能使用this.name=name; this.name繼承自父類,但是被private修飾。 super(name); this.strain = strain; } public static void main(String[] args) { // 1.創建寵物對象pet並輸出信息 Pet pet = new Pet("貝貝"); pet.print(); // 2.創建狗狗對象dog並輸出信息 Dog dog = new Dog("歐歐","雪納瑞"); //子類繼承父類原有的屬性和方法 dog.print(); System.out.println(dog.love); } }
3.2 直接重寫父類中的方法。
重寫(又叫覆蓋)是繼承的實現方式之一,也就是說只有在子類中才會出現方法的重寫。重寫是指在子類中保留父類成員方法的名稱不變,參數列表不變,重寫成員方法的實現內容,修改成員方法的返回值類型,或更改成員方法的存儲權限。(修改存儲權限只能從小的範圍到大的範圍修改,例如private可以修改為public,但是反向出錯)
package com.java.test; class ExtendsTest{ protected int adds(int a,int b){ int s=0; s=a+b; return s; } protected ExtendsTest doIt(){ return null; } } public class tests extends ExtendsTest{ //重寫成員方法的實現內容,修改成員方法的存儲權限 public int adds(int a,int b){ return a; } //修改成員方法的返回值類型 protected tests doIt(){ return null; } //重構,只重寫實現內容 protected int adds(int a,int b){ System.out.println("重構"); return a+b; } }
4.父類中不能被子類繼承的內容
4.1 父類中的構造函數不能被子類繼承
構造函數必須與類名一致,並且不能有返回值(包括void),主要作用是完成對象的初始化工作。構造函數總是伴隨著new操作一起執行,且不能由程序的編寫者直接調用,必須要由系統調用,且只在對象實例化時自動調用一次(普通方法可以被對象調用多次)。
當父類沒有提供無參的構造函數時,子類的構造函數必須顯式地調用父類的構造函數,如果父類提供了無參數的構造函數,子類可以不顯式調用父類的構造函數,編譯器默認會調用父類提供的無參構造函數。當有父類時,在實例化對象時會先執行父類的構造函數,然後執行子類的構造函數。
package zhishidian; class FathersClass{ public FathersClass(String s){ System.out.println("父類的構造函數執行"); } } public class ConstructorTest extends FathersClass{ /* * 當父類沒有提供無參數的構造方法時,子類的構造函數(子類的構造函數可以有參數也可以沒有參數)中必須顯式 * 地調用父類的構造函數,使用super(參數名)調用,若沒有顯示調用,出錯; * 當父類提供了無參的構造方法時,子類不需要顯式調用父類的無參構造方法,編譯器會默認調用父類的構造方法; * */ public ConstructorTest() { super("s"); System.out.println("子類的構造函數執行"); } public static void main(String[] args){ //ConstructorTest繼承了FathersClass,繼承父類就是要獲得其成員變量成員方法, ConstructorTest ct=new ConstructorTest(); } }
運行結果:
父類的構造函數執行 子類的構造函數執行
父類中沒有無參的構造函數,若在子類的構造方法中不使用super("s")進行顯式調用父類的有參構造函數,出錯:
4.2 父類中被private和default修飾的成員變量和方法不能被子類繼承
子類只能繼承父類的非私有(被public和protected修飾)的成員變量和方法。
理解java的三大特性之繼承