面向?qū)ο笾^承俏脊,多態(tài)

類與類之間的三種關(guān)系
類與類之間有三種關(guān)系
is a:繼承關(guān)系艘包,例如:公共汽車is a汽車
use a:使用關(guān)系,例如:人 use a 鉗子
has a:包含關(guān)系寨典,例如:人has a 胳膊

繼承的好處

  • 繼承的出現(xiàn)提高了代碼的復(fù)用性熏迹,提高軟件開發(fā)的效率
  • 繼承的出現(xiàn)讓類與類之間產(chǎn)生了關(guān)系,提供了多態(tài)的前提

繼承的定義格式

在程序中凝赛,如果想申明一個(gè)類繼承另一個(gè)類注暗,需要使用extends關(guān)鍵字

class 子類 extends 父類 {
    
}

使用繼承

案例:公司有2個(gè)部門坛缕,人事部和研發(fā)部,各自屬性如下


定義人事部類

public class PersonalDepartment {
    private int ID;// 部門編號(hào)
    private String name = "待定";// 部門名稱
    private int amount = 0;// 部門人數(shù)
    private String responsibility = "待定";// 部門職責(zé)
    private String manager = "無名氏";// 部門經(jīng)理
    private int count;//招聘人數(shù)

    public PersonalDepartment() {
    }

    public PersonalDepartment(int ID, String name, int amount, String responsibility, String manager, int count) {
        this.ID = ID;
        this.name = name;
        this.amount = amount;
        this.responsibility = responsibility;
        this.manager = manager;
        this.count = count;
    }

定義研發(fā)部

/**
 * 研發(fā)部
 */
public class ResourceDepartment {
    private int ID;// 部門編號(hào)
    private String name = "待定";// 部門名稱
    private int amount = 0;// 部門人數(shù)
    private String responsibility = "待定";// 部門職責(zé)
    private String manager = "無名氏";// 部門經(jīng)理
    private String speciality =null;//研發(fā)方向

    public ResourceDepartment() {
    }

    public ResourceDepartment(int ID, String name, int amount, String responsibility, String manager, String speciality) {
        this.ID = ID;
        this.name = name;
        this.amount = amount;
        this.responsibility = responsibility;
        this.manager = manager;
        this.speciality = speciality;
    }
    ......

問題:兩個(gè)類中的屬性有相同的部分捆昏,代碼冗余赚楚。解決辦法是將兩個(gè)部門共性的屬性抽取出來,放在父類中骗卜,然后讓兩個(gè)部門繼承父類宠页。

定義父類:兩個(gè)部門共性的屬性抽取到父類中

/** 部門父類:存放所有子類共性的內(nèi)容 */public class Deparment {    private int ID;// 部門編號(hào)    private String name = "待定";// 部門名稱    private int amount = 0;// 部門人數(shù)    private String responsibility = "待定";// 部門職責(zé)    private String manager = "無名氏";// 部門經(jīng)理        

子類修改如下:

    1. 共性的屬性刪除
    1. 共性屬性的get和set方法刪除
    1. 構(gòu)造方法做調(diào)整
/**
 * 人事部
 */
public class PersonalDepartment {
    private int count;//招聘人數(shù)

    public PersonalDepartment() {
    }

    public PersonalDepartment(int count) {
        
        this.count = count;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}
/**
 * 研發(fā)部
 */
public class ResourceDepartment {

    private String speciality =null;//研發(fā)方向

    public ResourceDepartment() {
    }

    public ResourceDepartment(String speciality) {
        this.speciality = speciality;
    }

    public String getSpeciality() {
        return speciality;
    }

    public void setSpeciality(String speciality) {
        this.speciality = speciality;
    }
}

讓人事部和研發(fā)部繼承部門的父類

  • 使用extends Deparment繼承部門類
  • 人事部
public class PersonalDepartment extends Deparment{
    private int count;//招聘人數(shù)

    public PersonalDepartment() {
    }

    public PersonalDepartment(int count) {

        this.count = count;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}
* 使用extends Deparment繼承部門類
/**
 * 研發(fā)部
 */
public class ResourceDepartment extends Deparment{

    private String speciality =null;//研發(fā)方向

    public ResourceDepartment() {
    }

    public ResourceDepartment(String speciality) {
        this.speciality = speciality;
    }

    public String getSpeciality() {
        return speciality;
    }

    public void setSpeciality(String speciality) {
        this.speciality = speciality;
    }
}

驗(yàn)證子類是否真的從父類繼承了數(shù)據(jù)

驗(yàn)證方法:

  • 創(chuàng)建人事部和研發(fā)部的對(duì)象,如果能夠調(diào)用出父類的方法寇仓,證明繼承了

創(chuàng)建一個(gè)公司類举户,測(cè)試一下:

/**
 * 公司類
 */
public class Company {
    public static void main(String[] args) {
        //創(chuàng)建人事部對(duì)象
        PersonalDepartment personalDepartment = new PersonalDepartment();
        //創(chuàng)建研發(fā)部對(duì)象
        ResourceDepartment resourceDepartment = new ResourceDepartment();
        //調(diào)用父類的方法
        System.out.println(personalDepartment.getName()); //getName()是父類的
        System.out.println(resourceDepartment.getName()); //getName()是父類的
    }
}

如上:

  • 實(shí)現(xiàn)代碼復(fù)用
  • 父類可以控制子類能繼承什么,通過封裝控制
    注意:對(duì)象的屬性可以通過方法賦值

創(chuàng)建子類對(duì)象時(shí)的運(yùn)行規(guī)則

  • 第一個(gè)方面:構(gòu)造函數(shù)的調(diào)用順序問題
    1. new子類時(shí)遍烦,首先調(diào)用子類構(gòu)造函數(shù)俭嘁,但是不執(zhí)行子類構(gòu)造函數(shù)
    2. 子類構(gòu)造函數(shù)被調(diào)用后立即調(diào)用父類的構(gòu)造函數(shù)。
  • 第二個(gè)方面:屬性初始化順序的問題
    1. 從Object類開始初始化
    2. 然后依次從父到子的順序初始化(哪個(gè)類定義的屬性服猪,就由哪個(gè)類負(fù)責(zé)初始化)
      子類通過關(guān)鍵字super()調(diào)用父類的構(gòu)造函數(shù)
  • super()必須放在子類構(gòu)造函數(shù)的第一行代碼

繼承的注意事項(xiàng)

類只支持單繼承供填,不允許多繼承

class A{} 
class B{}
class C extends A,B{}  // C類不可以同時(shí)繼承A類和B類

多個(gè)類可以繼承一個(gè)父類

class A{}
class B extends A{}
class C extends A{}   // 類B和類C都可以繼承類A

允許多層繼承

class A{}
class B extends A{}   // 類B繼承類A,類B是類A的子類
class C extends B{}   // 類C繼承類B罢猪,類C是類B的子類近她,同時(shí)也是類A的子類

子類和父類是一種相對(duì)概念

也就是說一個(gè)類是某個(gè)類父類的同時(shí),也可以是另一個(gè)類的子類膳帕。例如上面的這種情況中粘捎,B類是A類的子類,同時(shí)又是C類的父類危彩。

繼承的體系 之 Object類

Object是所有類的父類
如果一個(gè)類沒有顯示定義父類攒磨,那么默認(rèn)繼承Object類
Object類中沒有定義屬性,但是定義了12個(gè)方法恬砂,并且這些方法都是實(shí)例方法咧纠。因此每個(gè)對(duì)象都擁有這14個(gè)方法蓬痒。



繼承過程分析(父子類的實(shí)例話順序)
當(dāng)new子類時(shí)泻骤,父類也new了

執(zhí)行:從父到子

調(diào)用:從子到父

哪個(gè)類定義的屬性,就由哪個(gè)類賦值初始化梧奢,對(duì)于父類來說狱掂,初始化的數(shù)據(jù)是由子類通過super(數(shù)據(jù))傳入給父類的

繼承后子類的成員的變化

    了解了繼承給我們帶來的好處,提高了代碼的復(fù)用性亲轨。繼承讓類與類或者說對(duì)象與對(duì)象之間產(chǎn)生了關(guān)系趋惨。那么,當(dāng)繼承出現(xiàn)后惦蚊,類的成員之間產(chǎn)生了那些變化呢器虾?

    子類中的成員包括
  • 子類自己定義的屬性和方法
  • 從父類繼承的屬性和方法
  • 子類不能使用從父類繼承的私有成員讯嫂,因?yàn)楸环庋b了。

this和super

繼承中的this(調(diào)用子類成員)

  • this可以調(diào)用子類成員
  • this可以調(diào)用子類重載的構(gòu)造函數(shù)兆沙,必須是子類構(gòu)造函數(shù)的第一行

繼承中的super(調(diào)用父類成員)

  • super調(diào)用父類成員
  • super調(diào)用父類構(gòu)造函數(shù)欧芽,必須是子類構(gòu)造函數(shù)的第一行

this和super

this代表自己,this可以調(diào)用

  • 自己的屬性和方法
  • 在奔類的構(gòu)造函數(shù)內(nèi)調(diào)用其他構(gòu)造函數(shù)

super代表父類葛圃,super可以調(diào)用

  • 父類的屬性和方法
  • 在子類構(gòu)造中調(diào)用父類構(gòu)造

this和static

this表示實(shí)例

static表示靜態(tài)

static不能調(diào)實(shí)例

對(duì)象名可以調(diào)用static千扔,但是this確不能調(diào)用static

方法重寫(override)

如果子類從父類繼承的方法不能滿足子類的需要,或者不適合子類的需要库正。

此時(shí)子類可以將從父類繼承的方法重寫定義成滿足自己需要的方法曲楚。

重新定義稱為重寫。

class Pet {//寵物
    public void sound(){
        System.out.println("寵物叫");
    }
}
class Dog extends Pet {//狗

    //方法重寫
    @Override
    public void sound() {
        System.out.println("汪汪汪");
    }
}
class Cat extends Pet{//貓
    //方法重寫
    @Override
    public void sound(){
        System.out.println("喵喵喵");
    }
}

public class PetShop{//寵物店
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.sound();//調(diào)用狗的sound()
        Cat cat = new Cat();
        cat.sound();//調(diào)用貓的sound()
    }
}

注意事項(xiàng)

  • 在子類中將父類的方法再重新定義一遍
  • 方法重寫時(shí)褥符,方法的發(fā)返回值類型龙誊,方法名參數(shù)列表都要與父類一樣。
    *子類方法覆蓋父類方法属瓣,必須要保證權(quán)限大于等于父類權(quán)限
class Fu{   
    void show(){}
    public void method(){}
}
class Zi extends Fu{
    public void show(){}  //擴(kuò)大show的訪問權(quán)限载迄,編譯運(yùn)行沒問題
    void method(){}       //縮小method的訪問權(quán)限,編譯錯(cuò)誤
}
  • 方法重寫時(shí)抡蛙,子類不能縮小父類拋出的異常护昧。
class Pet {//寵物
    public void sound() throws RuntimeException{
        System.out.println("寵物叫");
        
    }
}
class Cat extends Pet{//貓
    //方法重寫
    public void sound() throws Exception{//錯(cuò)誤,因?yàn)镋xception 小于 RuntimeException
        System.out.println("喵喵喵");
    }
}

方法重載與方法重寫的區(qū)別

  • 方法重載:
    1.在同一類中(包括從父類繼承的)方法同名不同參與返回值無關(guān)
    *方法重寫:
    1.方法重寫存在于繼承關(guān)系中
    2.父子類之間的方法同名粗截,同參惋耙,同返回
    里氏替換原則(父類引用指向子類實(shí)例)
    實(shí)現(xiàn):

  • 設(shè)計(jì)寵物類,貓類熊昌,狗類绽榛,讓貓和狗繼承寵物類

  • 在寵物類中定義sound方法,表示寵物的叫聲婿屹,但是叫聲不能由具體的行為灭美。

  • 貓和狗重寫父類的sound方法,以實(shí)現(xiàn)具體的叫聲

class Pet {//寵物
    public void sound() throws RuntimeException{

    }
}
class Dog extends Pet {//狗

    //方法重寫
    @Override
    public void sound() {
        System.out.println("汪汪汪");
    }
}
class Cat extends Pet{//貓
    //方法重寫
    @Override
    public void sound() throws RuntimeException{
        System.out.println("喵喵喵");
    }
}

實(shí)現(xiàn):購買寵物要求寵物叫一聲昂利,以此判斷是否買它代碼如下:

public class PetShop{//寵物店
    public static void main(String[] args) {
        Pet pet= null
        pet=new Dog();
        pet.sound();
    }
}

"運(yùn)行結(jié)果:汪汪汪"

  • 父類引用pet 賦值時(shí) 賦的是子類對(duì)象Dog的實(shí)例届腐。就是這行代碼 pet = new Dog();

  • 我們發(fā)現(xiàn) pet = new Dog(); 這行代碼 = 的右側(cè) new的是子類的實(shí)例,而 = 左側(cè) 是父類的引用蜂奸。我們把這種情況稱為“父類引用指向子類實(shí)例”

"父類引用指向子類對(duì)象的結(jié)論"

  • 父類引用可以代表任何其子類對(duì)象犁苏,代碼表現(xiàn)為 Pet pet = new Dog() 或者

  • 父類引用指向哪個(gè)子類對(duì)象,調(diào)用的方法就是哪個(gè)子類中的方法扩所。例如:

    Pet pet = new Dog();
    pet.sound(); //調(diào)用Dog的sound方法
    pet = new Cat();
    pet.sound(); //調(diào)用Cat的sound方法
    
  • 父類引用指向子類對(duì)象其實(shí)是增強(qiáng)了父類的功能围详。
    注意:
    因?yàn)楦割愐谜{(diào)用方法時(shí),必須知道子類有哪些方法祖屏,知道的才能調(diào)用助赞,不知道的是不能調(diào)用的买羞。子類Cat新增的climb()方法父類并不知道,但是父類一定知道子類從父類繼承的方法雹食。所以父類引用只能調(diào)用子類與父類保持繼承關(guān)系的方法哩都。可以是重寫的方法婉徘。

子類引用指向父類實(shí)例:

 public static void main(String[] args) {
        pet pet = null;
        Dog dog = pet;//報(bào)錯(cuò): 子類引用dog指向父類實(shí)例
    }
  • 當(dāng)子類指向父類引用時(shí)漠嵌,子類會(huì)丟失數(shù)據(jù),因此不允許轉(zhuǎn)換盖呼。
  • 如果非要轉(zhuǎn)儒鹿,就要強(qiáng)轉(zhuǎn),認(rèn)可丟失的數(shù)據(jù)几晤。Dog dog = (Dog)pet;

里氏替換原則的調(diào)用規(guī)則:

  • 當(dāng)子類指向父類引用時(shí)约炎,子類會(huì)丟失數(shù)據(jù),因此不允許轉(zhuǎn)換蟹瘾。
  • 如果非要轉(zhuǎn)圾浅,就要強(qiáng)轉(zhuǎn),認(rèn)可丟失的數(shù)據(jù)憾朴。Dog dog = (Dog)pet;

final關(guān)鍵字

實(shí)現(xiàn):

  • 類的屬性不允許修改
  • 類的方法不允許覆蓋
  • 類不允許繼承
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末狸捕,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子众雷,更是在濱河造成了極大的恐慌灸拍,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砾省,死亡現(xiàn)場(chǎng)離奇詭異鸡岗,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)编兄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門轩性,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人狠鸳,你說我怎么就攤上這事揣苏。” “怎么了碰煌?”我有些...
    開封第一講書人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵舒岸,是天一觀的道長绅作。 經(jīng)常有香客問我芦圾,道長,這世上最難降的妖魔是什么俄认? 我笑而不...
    開封第一講書人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任个少,我火速辦了婚禮洪乍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘夜焦。我一直安慰自己壳澳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開白布茫经。 她就那樣靜靜地躺著巷波,像睡著了一般。 火紅的嫁衣襯著肌膚如雪卸伞。 梳的紋絲不亂的頭發(fā)上抹镊,一...
    開封第一講書人閱讀 50,096評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音荤傲,去河邊找鬼垮耳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛遂黍,可吹牛的內(nèi)容都是我干的终佛。 我是一名探鬼主播,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼雾家,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼铃彰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起芯咧,我...
    開封第一講書人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤豌研,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后唬党,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鹃共,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年驶拱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了霜浴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蓝纲,死狀恐怖阴孟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情税迷,我是刑警寧澤永丝,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站箭养,受9級(jí)特大地震影響慕嚷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一喝检、第九天 我趴在偏房一處隱蔽的房頂上張望嗅辣。 院中可真熱鬧,春花似錦挠说、人聲如沸澡谭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛙奖。三九已至,卻和暖如春杆兵,著一層夾襖步出監(jiān)牢的瞬間外永,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來泰國打工拧咳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留伯顶,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓骆膝,卻偏偏與公主長得像祭衩,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子阅签,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容