【從零開始學Java筆記】繼承

大家可以關(guān)注作者的賬號,關(guān)注從零開始學Java筆記文集。也可以根據(jù)目錄前往作者的博客園博客進行學習。本片文件將基于黑馬程序員就業(yè)班視頻進行學習以及資料的分享,并記錄筆記和自己的看法。歡迎大家一起學習和討論。

【從零開始學Java筆記】目錄

什么是繼承?

繼承就是子類繼承父類的特征和行為,使得子類對象(實例)具有父類的實例域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為。

簡單的說就是多個類有相同的成員變里和成員方法,為了避免代碼的重復(fù),可以先寫一個父類,包含共同的屬性,然后再由子類繼承。

關(guān)鍵字:extends

下面舉個例子:

  1. 不使用繼承
class GuanYu{
    String name;
    int age;
    String address;
    
    public void win() {
        System.out.println("關(guān)羽贏了!");
    }
    
    public void lose() {
        System.out.println("關(guān)羽輸了!");
    }
}

class LvBu{
    String name;
    int age;
    String address;
    
    public void win() {
        System.out.println("呂布贏了!");
    }
    
    public void lose() {
        System.out.println("呂布輸了!");
    }
}

可以看出無論是關(guān)羽還是呂布都擁有成員變量:姓名,年齡和地址成員方法:贏和輸。如果想寫一百個武將,十分繁瑣。所以使用繼承,寫一個父類,先尋找他們的共性,那就是他們都是人,所以寫一個people類,包含他們共同的屬性和方法。如下:

class Person{
    
    String name;
    int age;
    String address;
    
    public void win() {
        System.out.println("關(guān)羽贏了!");
    }
    
    public void lose() {
        System.out.println("關(guān)羽輸了!");
    }
}
class GuanYu extends Person{
    
}

class LvBu extends Person{
    
}

Java中維承的特點

  • Java語言只支持單一繼承,只能繼承一個父類(一個兒子只能有一個親爹)
    Java語言支持多層繼承(一個兒子可以有一個親爹, 還可以有一個親爺爺)

繼承中成員變量的特點

  • 子類只能獲取父類非私有成員
    子父類中成員變量的名字不一樣 直接獲取父類的成員變里
    子父類中成員變量名字是一樣的獲取的是子類的成員變量
class GuanYu{
    private String wifeName = "null";
    String name = "GuanYu";
    
}

class GuanXing extends GuanYu{
    String name = "GuanXing";//如果沒有這句,show()輸出GuanYu
    
    public void show() {
//      System.out.println(wifename); 子類無法繼承父類的私有變量,報錯
        System.out.println(name);//輸出GuanXing
    }

給大家出一道題,大家思考一下三個輸出語句的結(jié)果,如果能理解基本上就沒什么問題了
這里為大家補充一個就近原則:誰離我近我就用誰
如果有局部變量就使用局部變量
如果沒有局部變量,有子類的成員變量就使用子類的成員變量
如果沒有局部變量和子類的成員變量,有父類的成員變量就使用父類的成員變量
啥都沒有,出錯了! ! !|

class GuanYu{
    
    String name = "關(guān)羽";
    
}

class GuanXing extends GuanYu{
    String name = "關(guān)興";
    public void show() {
        String name = "關(guān)平";
        
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
}

super :可以獲取父類的成員變量和成員方法
this:可以獲取當前類的成員變量和成員方法

輸出結(jié)果
關(guān)平
關(guān)興
關(guān)羽

繼承中成員方法的特點

和成員變量相似

  • 子類中沒有這個方法,調(diào)用父類的
    子類中重寫了這個方法,調(diào)用子類的

重寫和重載的區(qū)別
方法的重寫:在子父類當中,子類的方法和父類的完全一樣,子類重寫了父類的方法(覆蓋),當子類重寫了父類的方法之后,使用子類對象調(diào)用的就是子類的方法
方法的重載:在一個類中,有多個重名的方法,但是其參數(shù)不一樣(參數(shù)的個數(shù),參數(shù)的類型,參數(shù)的順序),和返回值無關(guān)

方法重寫的應(yīng)用場景

  • 當父類的方法不能完全滿足子類使用,這個時候子類重寫父類的方法
    并可以在方法中使用關(guān)鍵字super調(diào)用父類的方法,這樣做即可以保有父類的功能,也可以擁有子類持有的功能

這里給大家舉個例子

class GuanYu{
    public void attack() {
        System.out.println("拖刀");
    }
}

class GuanXing extends GuanYu{
    public void attack() {
        super.attack();
        System.out.println("斬");
    }

其實很簡單,關(guān)興繼承了父親的攻擊方式,但是在拖刀的前提下加入了斬,使威力更強。這里為什么使用super.attack()為什么不直接復(fù)制過來,這里可以想象拖刀是一個很復(fù)雜的過程,但是我們這里簡寫,如果關(guān)羽攻擊的函數(shù)有1000行代碼,調(diào)用比復(fù)制更方便,也更好看。

方法重寫的注意事項

不能重寫父類私有的方法
權(quán)限必須大于等于父類方法的權(quán)限(了解即可)

注解: @ 一般寫在方法、變量、類前面,用來描述方法、變量、類,目的是提高代碼規(guī)范

還用剛才那個例子

class GuanYu{
    public void attack() {
        System.out.println("拖刀");
    }
}

class GuanXing extends GuanYu{
//  public void attck() {
//      super.attack();
//      System.out.println("斬");
//  }
    public void attack(String a) {
        super.attack();
        System.out.println("斬");
    }

如果我們給子類的方法加一個形參 string a ,或者錯寫成attck()并不會報錯,但是這個已經(jīng)不算是方法的重寫了

這時候我們在重寫的代碼前加上@Override,就會報錯。

繼承中構(gòu)造方法的執(zhí)行順序

public class ExtendsDemo2 {
    public static void main(String[] args) {
        GuanYu gy = new GuanYu();
        System.out.println("****************");
        GuanXing gx = new GuanXing();
        
    }
    

}

class GuanYu{

    public GuanYu() {
        System.out.println("這是關(guān)羽的無參構(gòu)造");
    }
    public GuanYu(int a) {
        System.out.println("這是關(guān)羽的有參構(gòu)造");
    }
    
}

class GuanXing extends GuanYu{
    public GuanXing() {
        System.out.println("這是關(guān)興的無參構(gòu)造");
    }
    public GuanXing(int a) {
        System.out.println("這是關(guān)興的有參構(gòu)造");
    }
    
}

輸出結(jié)果

這是關(guān)羽的無參構(gòu)造
****************
這是關(guān)羽的無參構(gòu)造
這是關(guān)興的無參構(gòu)造

為什么調(diào)用子類的無參構(gòu)造的時候,也會調(diào)用父類的無參構(gòu)造?
在有子父類繼承關(guān)系的類中,創(chuàng)建子類的對象,調(diào)用子類的構(gòu)造方法,如果子類構(gòu)造方法的第一行代碼沒有調(diào)用父類的構(gòu)造方法,則會默認的調(diào)用父類的無參構(gòu)造

我們可以使用super( )在子類構(gòu)造方法的第一行中調(diào)用父類的構(gòu)造方法

class GuanXing extends GuanYu{
    public GuanXing() {
        //super(1);  //測試1
        //this(2); //測試2
        System.out.println("這是關(guān)興的無參構(gòu)造");
    }
    public GuanXing(int a) {
        System.out.println("這是關(guān)興的有參構(gòu)造");
    }

可以分別取消測試1和測試2的注釋,再運行,看看結(jié)果。

為什么會有這個設(shè)定呢?因為必須先執(zhí)行父類的構(gòu)造,要先給父類的成員變里進行初始化,子類可能會使用到。

this和super的區(qū)別

this:當前對象的引用
調(diào)用子類的成員變量
調(diào)用子類的成員方法
在子類的構(gòu)造方法第一行調(diào)用子類其他構(gòu)造方法
super:子類對象的父類引用
調(diào)用父類的成員變量
調(diào)用父類的成員方法
在子類的構(gòu)造方法第一行調(diào)用父類的構(gòu)造方法

繼承的優(yōu)缺點

優(yōu)點

  • 提高了代碼的復(fù)用性
  • 提高了代碼的可維護性

缺點

  • 類的耦合性增強了
  • 開發(fā)的原則:高內(nèi)聚低耦合
  • 內(nèi)聚:就是自己完成某件事情的能力
  • 耦合:類與類的關(guān)系

通俗易懂的來說就是繼承可以只通過修改父類的屬性來實現(xiàn)子類屬性的同步修改,這樣會很方便。例如,奧迪,寶馬都是汽車的子類,如果想讓所有品牌汽車的價格增加15%,只需要再父類里面進行操作即可。但是同時也會出現(xiàn)問題,父類的屬性進行修改,子類的屬性必定進行修改,但有時或出現(xiàn)錯誤。例如刪掉增加15%的價格,所有的品牌都會自動刪除,如果有一些其他和價格有關(guān)的方法就會出現(xiàn)錯誤。其實這樣就是高耦合的表現(xiàn),類與類之間關(guān)系十分緊密,牽一發(fā)而動全身。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容