重新認(rèn)識(shí)java(三) ---- 面向?qū)ο笾^承忧便!

學(xué)習(xí)一個(gè)新知識(shí)的第一步,就是要知道它是什么帽借,然后要知道為什么要用它珠增,最后要知道如何使用它。這篇文章砍艾,我們重新認(rèn)識(shí)一下java中的繼承蒂教。

繼承是個(gè)什么東西

我們先來看一下上一篇文章中的代碼:

你會(huì)發(fā)現(xiàn),這兩個(gè)類中都有name屬性脆荷,都有marry方法凝垛。一個(gè)人,不可能只有名字吧简烘。他還有年齡苔严,地址,手機(jī)號碼孤澎,身份證號碼届氢,身高,體重巴拉巴拉的覆旭。除了男人和女人退子,還有小孩,老人型将,教師寂祥。。七兜。

如果我們每個(gè)類里都寫一遍name丸凭,age。腕铸。惜犀。也許你還沒寫完程序,自己就先累死了狠裹。不用我說虽界,大家也應(yīng)該知道了,沒錯(cuò)涛菠,我們需要繼承的幫助莉御。

我們把相同的屬性抽取出來撇吞,定義一個(gè)新的類Person,然后讓男人礁叔,女人都去繼承它牍颈,從而獲得Person的屬性,這樣晴圾,就大大簡化了我們的工作颂砸。

我們來嘗試一下。

//父類
public class Person {
    protected String name;
    protected int age;

    public void eat(){
        System.out.println("i am eating");
    }
}
//Man類 繼承Person
public class Man extends Person {
    private boolean hasBeard;

    public void showMan(){
        System.out.println("i am a man");
    }

    public boolean isHasBeard() {
        return hasBeard;
    }
}
//woman類 繼承Person
public class Woman extends Person{
    private boolean hasLongHair;

    public void shouWoman(){
        System.out.println("i am a woman");
    }

    public boolean isHasLongHair() {
        return hasLongHair;
    }
}

簡單的繼承我想大家都懂死姚,我就不多說占用篇幅了。

繼承的特點(diǎn)

我們已經(jīng)知道了什么是繼承勤篮,那么繼承有沒有什么限制呢都毒?

1.java中只支持單繼承

也就是說,一個(gè)類只能夠有一個(gè)父類碰缔。但是java支持“多重繼承”账劲。

單繼承:

class A(){}
class B extends A (){} 

多重繼承:

class A{}
class B extends A {} 
class C extends B {} 

為什么java不支持多繼承呢?因?yàn)槿菀自斐刹槐匾幕靵y金抡。比如說:

  • 結(jié)構(gòu)復(fù)雜化:如果是單一繼承瀑焦,一個(gè)類的父類是什么,父類的父類是什么梗肝,都很明確榛瓮,因?yàn)橹挥袉我坏睦^承關(guān)系,然而如果是多重繼承的話巫击,一個(gè)類有多個(gè)父類禀晓,這些父類又有自己的父類,那么類之間的關(guān)系就很復(fù)雜了坝锰。
  • 優(yōu)先順序模糊:假如我有A粹懒,C類同時(shí)繼承了基類,B類繼承了A類顷级,然后D類又同時(shí)繼承了B和C類凫乖,所以D類繼承父類的方法的順序應(yīng)該是D、B弓颈、A帽芽、C還是D、B恨豁、C嚣镜、A,或者是其他的順序橘蜜,很不明確菊匿。
  • 功能沖突:因?yàn)槎嘀乩^承有多個(gè)父類付呕,所以當(dāng)不同的父類中有相同的方法是就會(huì)產(chǎn)生沖突。如果B類和C類同時(shí)又有相同的方法時(shí)跌捆,D繼承的是哪個(gè)方法就不明確了徽职,因?yàn)榇嬖趦煞N可能性。

當(dāng)然佩厚,多繼承的這些問題很多語言已經(jīng)解決了姆钉,比如c++,python等抄瓦,但并不是所有的語言都有必要去解決這個(gè)問題潮瓶。java的類雖然不能實(shí)現(xiàn)多繼承,但是java的接口支持多實(shí)現(xiàn)钙姊,這個(gè)我們講到接口的時(shí)候再說毯辅。

對多繼承感興趣的可以google一下mixin(混入),還可以去看一下基于java8的mixin實(shí)現(xiàn)(大多數(shù)都是線程不安全的煞额,不要隨便用)思恐。

2.子類擁有父類非private的屬性,方法

也就是說膊毁,父類的屬性或者方法如果是peivate的胀莹,那么子類是不能繼承它的。講到這里婚温,就必須得提一下四個(gè)修飾符了:

---- 本類 同包(無關(guān)類或子類) 不同包(子類) 不同包(無關(guān)類)
private ?
default ? ?
protected ? ? ?
public ? ? ? ?

在java中描焰,protected關(guān)鍵字大展身手的地方就是在繼承中$哉伲《thinking in java》中是這樣介紹protected的:

在理想世界中栈顷,僅靠關(guān)鍵字private已經(jīng)足夠了。但在實(shí)際項(xiàng)目中嵌巷,經(jīng)常會(huì)想要將某些事物盡可能堆這個(gè)世界隱藏起來萄凤,但仍然允許導(dǎo)出的類的成員訪問他們。關(guān)鍵字protected就是起這個(gè)作用的搪哪。它指明”就類用戶而言靡努,這是privated,但是對于任何一個(gè)繼承于此類的導(dǎo)出類或其他任何一個(gè)位于同一個(gè)包內(nèi)的類來說晓折,他卻是可以訪問的”

怎么理解呢惑朦?寫個(gè)代碼你就明白了


package cn.pkgA
class A {
    protected String name;
}
class B extends A{}
class C {
    B b = new B();
    b.name;//可以訪問到
}
package cn.pkgB

class C {
    B b = new B();
    b.name;//訪問不到
}


3.子類可以擁有自己的屬性和方法漓概,即子類可以對父類進(jìn)行擴(kuò)展漾月。

如果子類只能有父類的屬性和方法,那要子類還有什么用胃珍?梁肿?

4.子類可以用自己的方式實(shí)現(xiàn)父類的方法蜓陌。

這個(gè)叫做函數(shù)重寫(覆蓋),我們一會(huì)會(huì)重點(diǎn)分析吩蔑。

構(gòu)造器

除了被peivate修飾的方法和變量之外钮热,父類的構(gòu)造器也不能被子類繼承。

但是父類的構(gòu)造器帶有參數(shù)的烛芬,則必須在子類的構(gòu)造器中顯式地通過super關(guān)鍵字調(diào)用父類的構(gòu)造器并配以適當(dāng)?shù)漠?dāng)屬列表隧期。

如果父類有無參構(gòu)造器,則在子類的構(gòu)造器中用super調(diào)用父類構(gòu)造器不是必須的赘娄,如果沒有使用super關(guān)鍵字仆潮,系統(tǒng)會(huì)自動(dòng)調(diào)用父類的無參構(gòu)造器。

我們給Person類添加一個(gè)構(gòu)造器:

public class Person {
    protected String name;
    protected int age;

    public void eat(){
        System.out.println("i am eating");
    }
    //帶參數(shù)的構(gòu)造器
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

這個(gè)時(shí)候擅憔,如果你不給子類添加構(gòu)造器并在第一行寫入super(name鸵闪,age),則會(huì)報(bào)錯(cuò):

在子類添加如下方法后錯(cuò)誤消失:

public Man(String name, int age/*, boolean hasBeard*/) {
    super(name, age);
    //this.hasBeard = hasBeard;
}

//注釋掉的地方可有可無

為什么會(huì)有這個(gè)要求呢暑诸?你一會(huì)就知道了,先賣個(gè)關(guān)子辟灰。

重寫與重載

重寫

重寫又叫覆蓋个榕,發(fā)生在繼承關(guān)系下的子類中。我們上面說過芥喇,子類可以用自己的方式實(shí)現(xiàn)父類的方法西采,重寫不能改變參數(shù)列表,也不能縮小方法的訪問權(quán)限继控,如果父類方法拋出異常械馆,子類拋出的異常不能比父類的異常“大”武通,也不能拋出新的異常霹崎。

我們Person類中有一個(gè)方法:

    public void eat(){
        System.out.println("i am eating");
    }

有一個(gè)子類修道成仙了,不吃飯冶忱,于是他可以在他自己的類里這樣改

    @Override  //這個(gè)是注解尾菇,表明這個(gè)方法是重寫了父類的方法,最好寫上
    public void eat(){
        System.out.println("i don't eat");
    }

這里提一下囚枪,子類重寫父類方法不能縮小父類方法的訪問權(quán)限但擴(kuò)大是可以的派诬。比如說父類有一個(gè)protected方法,子類重寫它的時(shí)候不能改為private链沼,但是可以改成public默赂。

這里還有一個(gè)不大不小的坑。如果你的父類方法是peivate的括勺,比如:

    private void eat(){
        System.out.println("i am eating");
    }

你可以在子類中這樣寫:

    public void eat(){
        System.out.println("i don't eat");
    }

但是缆八,這不是重寫G!R铩蜈缤!因?yàn)楦割惙椒ㄊ撬接械模宰宇惛緵]有得到eat()這個(gè)方法冯挎,子類的eat()方法是你重新定義的一個(gè)和父類沒有半毛錢的函數(shù)底哥。

重載

把重載放到這里講只是因?yàn)樗椭貙懹械娜簧瞪捣植磺宄剌d和繼承沒有任何關(guān)系(當(dāng)然房官,繼承之間也存在重載趾徽,也就是說,繼承可以重載翰守,但是重載不一定繼承)孵奶,它發(fā)生在類本身。重載方法的特點(diǎn)是方法名相同而參數(shù)列表不同蜡峰。

比如這樣:

public void count(int a , int b){
    System.out.println("a+b=" + (a+b));
}

public void count(int a , int b,int c){
    System.out.println("a+b=" + (a+b+c));
}

public void count(int a , int b ,double c){
    System.out.println("a+b=" + (a+b+c));
}

函數(shù)重載的特點(diǎn):

  • 被重載的方法必須改變參數(shù)列表(參數(shù)個(gè)數(shù)或類型或順序不一樣)了袁;
  • 被重載的方法可以改變返回類型;
  • 被重載的方法可以改變訪問修飾符湿颅;
  • 被重載的方法可以聲明新的或更廣的檢查異常(區(qū)別于重寫)载绿;
  • 方法能夠在同一個(gè)類中或者在一個(gè)子類中被重載。

注意:參數(shù)列表必須不同油航!

繼承的缺點(diǎn)

  • 繼承是一種強(qiáng)耦合關(guān)系崭庸,父類變,子類就必須變谊囚。
  • 繼承破壞了封裝怕享,對于父類而言,它的實(shí)現(xiàn)細(xì)節(jié)對與子類來說都是透明的镰踏。

提醒函筋!慎用繼承!

如果你知道高手寫代碼都想著怎么解耦你就知道這個(gè)缺點(diǎn)室友多么討厭了余境。

你可能會(huì)問驻呐,我不用繼承用什么?別急芳来,接下來的幾篇文章會(huì)告訴你含末。

昨天的遺留問題

看了上一篇文章的人可能還記得那個(gè)遺留問題。我們現(xiàn)在來解決一下:

//父類
public class Person {
    protected String name;
    
    public void marry(Person p){
        System.out.println("marry");
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
//man類
public class Man extends Person {
    private Woman wife;
    private double money;

    @Override
    public void marry(Person p) {
        this.wife = (Woman)p;
        p.marry(this);
    }
    //只有自己和妻子可以用錢
    public void setMoney(Person p,double money) {
        if (p == this || p == this.wife)
            this.money = money;
        else
            System.out.println(p.getName()+"搶錢即舌!");
    }

    public double getMoney() {
        return money;
    }
}
//woman類
public class Woman extends Person{
    private boolean hasLongHair;
    private Man husband;

    @Override
    public void marry(Person p) {
        this.husband = (Man)p;
    }
}

我們來看一下效果:

看起來還不錯(cuò)佣盒,不是么。

當(dāng)然顽聂,我更喜歡這么做

public void setMoney(Person p,double money) {
      if (p == this || p == this.wife)
          this.money = money;
      else if(money > this.money)
          this.money = money;
      else  
          System.out.println(p.getName()+"搶錢肥惭!");
}

總結(jié)

繼承還有很多知識(shí)點(diǎn)盯仪,比如向上轉(zhuǎn)型和向下轉(zhuǎn)型(上面解決上一篇問題的代碼就用到了這個(gè)知識(shí)點(diǎn)),在繼承中蜜葱,對象是怎么初始化的全景,靜態(tài)代碼塊的使用,final關(guān)鍵字的使用等等牵囤。

但是我打算先放一放再講爸黄,等寫完組合,聚合和多態(tài)再來討論這些知識(shí)會(huì)更好一點(diǎn)揭鳞。

下一篇《重新認(rèn)識(shí)java(四) --- 組合炕贵、聚合與繼承的愛恨情仇》敬請期待。


有錯(cuò)誤或者我沒講到的地方或者更好的思路請及時(shí)與我聯(lián)系野崇!

轉(zhuǎn)載請注明出處3瓶!E依妗1詈洹!
本文原創(chuàng)自csdn和簡書7龆啤脆霎!
csdn地址:http://blog.csdn.net/qq_31655965/article/details/53381737
簡書地址:http://www.reibang.com/p/4258962bebb6

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市狈惫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鹦马,老刑警劉巖胧谈,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異荸频,居然都是意外死亡菱肖,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進(jìn)店門旭从,熙熙樓的掌柜王于貴愁眉苦臉地迎上來稳强,“玉大人,你說我怎么就攤上這事和悦⊥艘撸” “怎么了?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵鸽素,是天一觀的道長褒繁。 經(jīng)常有香客問我,道長馍忽,這世上最難降的妖魔是什么棒坏? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任燕差,我火速辦了婚禮,結(jié)果婚禮上坝冕,老公的妹妹穿的比我還像新娘徒探。我一直安慰自己,他們只是感情好喂窟,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布测暗。 她就那樣靜靜地躺著,像睡著了一般谎替。 火紅的嫁衣襯著肌膚如雪偷溺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天钱贯,我揣著相機(jī)與錄音挫掏,去河邊找鬼。 笑死秩命,一個(gè)胖子當(dāng)著我的面吹牛尉共,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弃锐,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼袄友,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了霹菊?” 一聲冷哼從身側(cè)響起剧蚣,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎旋廷,沒想到半個(gè)月后鸠按,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饶碘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年目尖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扎运。...
    茶點(diǎn)故事閱讀 40,861評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瑟曲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出豪治,到底是詐尸還是另有隱情洞拨,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布鬼吵,位于F島的核電站扣甲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜琉挖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一启泣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧示辈,春花似錦寥茫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至险耀,卻和暖如春弄喘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背甩牺。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工蘑志, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贬派。 一個(gè)月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓急但,卻偏偏與公主長得像,于是被迫代替她去往敵國和親搞乏。 傳聞我的和親對象是個(gè)殘疾皇子波桩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評論 2 361

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