不會(huì)還有人沒(méi)有理解Java的繼承吧
Java大聯(lián)盟
致力于最高效的Java學(xué)習(xí)
關(guān)注
原文鏈接 https://blog.csdn.net/paperjie/article/details/132058107
什么是繼承
繼承(inheritance)機(jī)制: 是面向?qū)ο蟪绦蛟O(shè)計(jì)使代碼可以復(fù)用的最重要的手段,它允許程序員在保持原有類特性的基礎(chǔ)上進(jìn)行擴(kuò)展,增加新功能,這樣產(chǎn)生新的 類, 稱派生類 。 繼承呈現(xiàn)了面向?qū)ο蟪绦蛟O(shè)計(jì)的層次結(jié)構(gòu), 體現(xiàn)了由簡(jiǎn)單到復(fù) 雜的認(rèn)知過(guò)程。 繼承主要解決的問(wèn)題是: 共性的抽取,實(shí)現(xiàn)代碼復(fù)用
舉個(gè)栗子: 和貓都是動(dòng)物,那么我們就可以將共性的內(nèi)容進(jìn)行抽取,然后采用繼承的思想來(lái)達(dá)到共用

Dog和Cat都繼承了Animal類,其中: Animal類稱為 父類/基類或超類 ,Dog和Cat可以稱為Animal的 子類/派生類 ,繼承之后,子類可以復(fù)用父類中成員,子類在實(shí)現(xiàn)時(shí)只需關(guān)心自己新增加的成員即可。 從繼承概念中可以看出繼承最大的作用就是: 實(shí)現(xiàn)代碼復(fù)用,還有就是來(lái)實(shí)現(xiàn)多態(tài)

繼承的語(yǔ)法
在Java中如果要表示類之間的繼承關(guān)系,需要借助 extends關(guān)鍵字
使用繼承方式來(lái)設(shè)計(jì)代碼:


注意:
子類會(huì)將父類中的成員變量或者成員方法繼承到子類中了
子類繼承父類之后,必須要新添加自己特有的成員,體現(xiàn)出與基類的不同,否則就沒(méi)有必要繼承了
父類成員訪問(wèn)
子類中訪問(wèn)父類的成員變量
子類和父類不存在同名的成員變量


在子類方法中或者通過(guò)子類對(duì)象訪問(wèn)成員時(shí):
如果訪問(wèn)的成員變量子類中有,優(yōu)先訪問(wèn)自己的成員變量。
如果訪問(wèn)的成員變量子類中無(wú),則訪問(wèn)父類繼承下來(lái)的,如果父類也沒(méi)有定義,則 編譯報(bào)錯(cuò)。
如果訪問(wèn)的成員變量與父類中成員變量同名,則優(yōu)先訪問(wèn)自己的
簡(jiǎn)單來(lái)說(shuō),就是就近原則,自己有就先訪問(wèn)自己的,如果沒(méi)有則向父類找
子類中訪問(wèn)父類的成員方法
成員方法名不同:

成員方法沒(méi)有同名時(shí),在子類方法中或者通過(guò)子類對(duì)象訪問(wèn)方法時(shí),則優(yōu)先訪問(wèn)自 己的,自己沒(méi)有時(shí)再到父類中找,如果父類中也沒(méi)有則報(bào)錯(cuò)。
成員方法名相同:

通過(guò)子類對(duì)象訪問(wèn)父類與子類中不同名方法時(shí),優(yōu)先在子類中找,找到則訪問(wèn),否則在父類中找,找到則訪問(wèn),否則編譯報(bào)錯(cuò)。
通過(guò)派生類對(duì)象訪問(wèn)父類與子類同名方法時(shí),如果父類和子類同名方法的參數(shù)列表不同(重載),根據(jù)調(diào)用方法適傳遞的參數(shù)選擇合適的方法訪問(wèn),如果沒(méi)有則報(bào)錯(cuò)
super關(guān)鍵字
在java中,提供了super關(guān)鍵字,它的主要作用就是: 在子類方法中訪問(wèn)父類的成員。
子類方法中,如果想要明確訪問(wèn)父類中成員時(shí),借助super關(guān)鍵字即可

注意:
1. 只能在非靜態(tài)方法中使用(super和this都是引用對(duì)象,但靜態(tài)方法不會(huì)調(diào)用對(duì)像)
2. 在子類方法中,訪問(wèn)父類的成員變量和方法。
子類構(gòu)造方法
我們需要知道:子類對(duì)象構(gòu)造時(shí),需要先調(diào)用父類構(gòu)造方法,再執(zhí)行子類的構(gòu)造方法。

在子類構(gòu)造方法中,并沒(méi)有寫任何關(guān)于基類構(gòu)造的代碼, 但是在構(gòu)造子類對(duì)象時(shí),先執(zhí)行基類的構(gòu)造方法,然后執(zhí)行子類的構(gòu)造方法 ,因?yàn)椋?/span> 子類對(duì)象中成員是有兩部分組成的,基類繼承下來(lái)的以及子類新增加的部分 。 父子父子肯定是先有父再有子,所以在構(gòu)造子類對(duì)象時(shí)候 ,先要調(diào)用基類的構(gòu)造方法,將從基類繼承下來(lái)的成員構(gòu)造完整,然后再調(diào)用子類自己的構(gòu)造方法,將子類自己新增加的成員初始化完整
注意:
1. 若父類顯式定義無(wú)參或者默認(rèn)的構(gòu)造方法,在子類構(gòu)造方法第一行默認(rèn)有隱含的super()調(diào)用,即調(diào)用基類構(gòu)造方法
2. 如果父類構(gòu)造方法是帶有參數(shù)的,此時(shí)需要用戶為子類顯式定義構(gòu)造方法,并在子類 構(gòu)造方法中選擇合適的父類構(gòu)造方法調(diào)用,否則編譯失敗。
3. 在子類構(gòu)造方法中,super(...)調(diào)用父類構(gòu)造時(shí),必須是子類構(gòu)造函數(shù)中第一條語(yǔ)句。
4. super(...)只能在子類構(gòu)造方法中出現(xiàn)一次,并且不能和this同時(shí)出現(xiàn)
super和this關(guān)鍵字
相同點(diǎn):
1. 都是Java中的關(guān)鍵字
2. 只能在類的非靜態(tài)方法中使用,用來(lái)訪問(wèn)非靜態(tài)成員方法和字段
3. 在構(gòu)造方法中調(diào)用時(shí),必須是構(gòu)造方法中的第一條語(yǔ)句,并且不能同時(shí)存在
不同點(diǎn):
1.this是當(dāng)前對(duì)象的引用,當(dāng)前對(duì)象即調(diào)用實(shí)例方法的對(duì)象,super相當(dāng)于是子類對(duì)象中從父類繼承下來(lái)部分成員的引用
2. 在非靜態(tài)成員方法中,this用來(lái)訪問(wèn)本類的方法和屬性,super用來(lái)訪問(wèn)父類繼承下來(lái)的方法和屬性
3. 在構(gòu)造方法中:this(...)用于調(diào)用本類構(gòu)造方法,super(...)用于調(diào)用父類構(gòu)造方法,兩種調(diào)用不能同時(shí)在構(gòu)造方法中出現(xiàn)
4. 構(gòu)造方法中一定會(huì)存在super(...)的調(diào)用,用戶沒(méi)有寫編譯器也會(huì)增加,但是this(...)用戶不寫則沒(méi)有

再談初始化
實(shí)例代碼塊和靜態(tài)代碼塊,在沒(méi)有繼承關(guān)系時(shí)的執(zhí)行順序:

1. 靜態(tài)代碼塊先執(zhí)行,并且只執(zhí)行一次,在類加載階段執(zhí)行
2. 當(dāng)有對(duì)象創(chuàng)建時(shí),才會(huì)執(zhí)行實(shí)例代碼塊,實(shí)例代碼塊執(zhí)行完成后,最后構(gòu)造方法執(zhí)行
繼承關(guān)系上的執(zhí)行順序:



結(jié)論:
1、父類靜態(tài)代碼塊優(yōu)先于子類靜態(tài)代碼塊執(zhí)行,且是最早執(zhí)行
2、父類實(shí)例代碼塊和父類構(gòu)造方法緊接著執(zhí)行
3、子類的實(shí)例代碼塊和子類構(gòu)造方法緊接著再執(zhí)行
4、第二次實(shí)例化子類對(duì)象時(shí),父類和子類的靜態(tài)代碼塊都將不會(huì)再執(zhí)行
protected關(guān)鍵字
我們知道,為了實(shí)現(xiàn)封裝特性,Java中引入了訪問(wèn)限定符,主要限定:類或者類中成員能否在類外或者其他包中被訪問(wèn)。
我們的protected關(guān)鍵字就是針對(duì)與不同包的子類使用:

這里需要注意一點(diǎn):父類中private成員變量雖然在子類中不能直接訪問(wèn),但是也繼承到子類中
使用原則:
我們希望類要盡量做到 "封裝", 即隱藏內(nèi)部實(shí)現(xiàn)細(xì)節(jié), 只暴露出 必要 的信息給類的調(diào)用者.
因此我們?cè)谑褂玫臅r(shí)候應(yīng)該盡可能的使用 比較嚴(yán)格 的訪問(wèn)權(quán)限. 例如如果一個(gè)方法能用 private, 就盡量不要用 public.
另外, 還有一種 簡(jiǎn)單粗暴 的做法: 將所有的字段設(shè)為 private, 將所有的方法設(shè)為 public. 不過(guò)這種方式屬于是對(duì)訪問(wèn)權(quán)限的濫用, 還是更希望能寫代碼的時(shí)候認(rèn)真思考, 該類提供的字段方法到底給 "誰(shuí)" 使用(是類內(nèi)部自己用, 還是類的調(diào)用者使用, 還是子類使用)
繼承方式
Java中我們有幾種繼承方式:

這里我們要注意Java中不支持多繼承方式,我們并不希望類之間的繼承層次太復(fù)雜. 一般我們不希望出現(xiàn)超過(guò)三層的繼承關(guān)系. 如果繼承層次太多, 就需要考慮對(duì)代碼進(jìn)行重構(gòu)了 .如果想從語(yǔ)法上進(jìn)行限制繼承, 就可以 使用

