繼承
Java 繼承的實現(xiàn)(只支持類的單繼承盼樟,不支持類多繼承,但是支持接口的多實現(xiàn))。
多個類中存在相同屬性和行為時殖氏,將這些內(nèi)容抽取到單獨一個類. 定義類時直接通過 extends 關(guān)鍵字指明要繼承的父類。
子類對象除了可以訪問子類中直接定義的成員外姻采,可直接訪問父類的所有非私有成員雅采。
繼承的作用
- 繼承提高了代碼的復(fù)用性。
- 繼承的出現(xiàn)讓類與類之間產(chǎn)生了關(guān)系慨亲,提供了多態(tài)的前提婚瓜。
- 不要僅為了獲取其他類中某個功能而去強行使用繼承,類與類之間要有所屬( " is a " )關(guān)系)刑棵。
如何使用一個繼承體系中的功能
- 查閱父類功能(定義了共性的功能)
- 創(chuàng)建子類對象使用功能(因為父類可能不能創(chuàng)建對象, 而且子類提供了更豐富的功能)
- 繼承中自子類變量的特點:如果子類出現(xiàn)非私有的同名變量時, 子類訪問本類變量用 this, 子類訪問父類中的同名變量用 super巴刻。
成員變量的隱藏
子類成員變量與父類一樣,會屏蔽父類中的成員變量蛉签,稱為“成員變量隱藏”胡陪。
方法的覆蓋(Override)
如果子類方法完全與父類方法相同,即:相同的方法名碍舍、相同的參數(shù)列表和相同的返回值督弓,只是方法體不同,這稱為子類覆蓋(Override)父類方法乒验。
在聲明方法時最后添加@Override
注解愚隧,@Override
注解不是方法覆蓋必須的,但添加 @Override 注解有兩個好處:
- 提高程序的可讀性锻全。
- 編譯器檢查 @Override 注解的方法在父類中已定義的方法是否匹配狂塘,如果不匹配則會報錯。
方法覆蓋時應(yīng)遵循的原則
- 覆蓋后的方法不能比原方法有更嚴(yán)格的訪問控制(可以相同)鳄厌。例如將代碼訪問控制 public 修改 private荞胡,那么會發(fā)生編譯錯誤。
- 覆蓋后的方法不能比原方法產(chǎn)生更多的異常了嚎。
- 父類中的私有方法不可以被覆蓋泪漂。
- 子類的返回類型可以是父類的子類廊营。
覆蓋的應(yīng)用
- 當(dāng)子類需要父類的功能,而功能主體子類有自己特有內(nèi)容時萝勤,可以復(fù)寫父類中的方法露筒,這樣也沿襲了父類的功能
- 構(gòu)造方法在類繼承中的作用
構(gòu)造方法不能繼承.由于子類對象要對來自父類的成員進行初始化,因此,在創(chuàng)建子類對象時除了執(zhí)行子類的構(gòu)造方法外,還需要調(diào)用父類的構(gòu)造方法.具體遵循如下原則:- 當(dāng)子類未定義構(gòu)造方法時,創(chuàng)建對象時將無條件地調(diào)用父類的空構(gòu)造方法,會默認(rèn)在第一條添加super();
- 對于父類的含參數(shù)構(gòu)造方法,子類可以在自己構(gòu)造方法中使用關(guān)鍵字 super 來調(diào)用它, 但 super 調(diào)用語句必須是子類構(gòu)造方法中的第一個可執(zhí)行語句敌卓;
- 子類在自己定義構(gòu)造方法中如果沒有用 super 明確調(diào)用父類的構(gòu)造方法慎式,則在創(chuàng)建對象時,將自動先執(zhí)行父類的無參構(gòu)造方法,然后再執(zhí)行自己定義的構(gòu)造方法。
所以在一個類的設(shè)計時如果有構(gòu)造方法趟径,最好提供一個無參構(gòu)造方法瘪吏。例如系統(tǒng)類庫中的類大多提供了無參構(gòu)造方法,用戶編程時最好也要養(yǎng)成此習(xí)慣蜗巧。
【注意】使用 this 查找匹配的方法時首先在本類查找掌眠,找不到時再到其父類和祖先類查找;使用 super 查找匹配方法時幕屹,首先到直接父類查找蓝丙,如果不存在,則繼續(xù)到其祖先類逐級往高層查找香嗓。
繼承的更多細(xì)節(jié)
? 構(gòu)造方法迅腔;
在父類構(gòu)造方法中調(diào)用可被子類重寫的方法装畅,是一種不好的實踐靠娱,容易引起混淆,應(yīng)該只調(diào)用private的方法掠兄。
? 重名與靜態(tài)綁定像云;
靜態(tài)綁定在程序編譯階段即可決定。實例變量蚂夕、靜態(tài)變量迅诬、靜態(tài)方法、private 方法婿牍,都是靜態(tài)綁定的侈贷。
而動態(tài)綁定則要等到程序運行時。子類可以重寫父類非private的方法等脂,當(dāng)調(diào)用的時候俏蛮,會動態(tài)綁定,執(zhí)行子類的方法上遥。
? 重載和重寫搏屑;
重載是指方法名稱相同但參數(shù)簽名不同(參數(shù)個數(shù)、類型或順序不同)粉楚,重寫是指子類重寫與父類相同參數(shù)簽名的方法辣恋。
對一個函數(shù)調(diào)用而言亮垫,可能有多個匹配的方法,有時候選擇哪一個并不是那么明顯伟骨。當(dāng)有多個重名函數(shù)的時候饮潦,在決定要調(diào)用哪個函數(shù)的過程中,首先是按照參數(shù)類型進行匹配的底靠,換句話說害晦,尋找在所有重載版本中最匹配的,然后才看變量的動態(tài)類型暑中,進行動態(tài)綁定壹瘟。
? 父子類型轉(zhuǎn)換;
類型轉(zhuǎn)換有兩個方向:
- 將父類引用類型變量轉(zhuǎn)換為子類類型鳄逾,這種轉(zhuǎn)換稱為向下轉(zhuǎn)型(downcast)稻轨;
- 將子類引用類型變量轉(zhuǎn)換為父類類型,這種轉(zhuǎn)換稱為向上轉(zhuǎn)型(upcast)雕凹。向下轉(zhuǎn)型需要強制轉(zhuǎn)換殴俱,而向上轉(zhuǎn)型是自動的。
將父類引用賦值給子類變量時要進行強制轉(zhuǎn)換枚抵,強制轉(zhuǎn)換在編譯時總是認(rèn)可的线欲,但運行時的情況取決于對象的值.如果父類對象引用指向的就是該子類的一個對象,則轉(zhuǎn)換是成功的。否則會拋出ClassCastException
汽摹。如果不能確定實例是哪一種類型李丰,可以在轉(zhuǎn)型之前使用 instanceof
運算符進行判斷。
因此并不是所有的引用類型都能互相轉(zhuǎn)換逼泣,只有屬于同一棵繼承層次樹中的引用類型才可以轉(zhuǎn)換趴泌。
? 可見性重寫;
重寫方法時拉庶,一般并不會修改方法的可見性嗜憔。但我們還是要說明一點,重寫時氏仗,子類方法不能降低父類方法的可見性吉捶。
為什么要這樣規(guī)定呢?繼承反映的是“is-a”的關(guān)系皆尔,即子類對象也屬于父類呐舔,子類必須支持父類所有對外的行為,將可見性降低就會減少子類對外的行為床佳,從而破壞“is-a”的關(guān)系滋早,但子類可以增加父類的行為,所以提升可見性是沒有問題的砌们。
舉例:
// 父類
Object lalala(Integer x) throws IllegalArgumentException {
// 子類
@Override
Integer lalala(Integer x);
子類只能拋出范圍內(nèi)或者更小的異常杆麸,返回類型也只能更小搁进,但是方法的可見性可以更大。雖然重寫方法時昔头,一般并不會修改方法的簽名饼问。
? 防止繼承(final)
final關(guān)鍵字可以修飾變量,也可修飾final 使成為最終類揭斧。
繼承是把雙刃劍
繼承破壞封裝什么是封裝呢莱革?封裝就是隱藏實現(xiàn)細(xì)節(jié),提供簡化接口讹开。使用者只需要關(guān)注怎么用盅视,而不需要關(guān)注內(nèi)部是怎么實現(xiàn)的。實現(xiàn)細(xì)節(jié)可以隨時修改旦万,而不影響使用者闹击。
繼承可能破壞封裝是因為子類和父類之間可能存在著實現(xiàn)細(xì)節(jié)的依賴。子類在繼承父類的時候成艘,往往不得不關(guān)注父類的實現(xiàn)細(xì)節(jié)赏半,而父類在修改其內(nèi)部實現(xiàn)的時候,如果不考慮子類淆两,也往往會影響到子類断箫。
繼承既強大又有破壞性,那怎么辦呢秋冰?1)避免使用繼承仲义;2)正確使用繼承。
怎么避免繼承的有三種方法:
? 使用final關(guān)鍵字丹莲;
? 優(yōu)先使用組合而非繼承光坝;
? 使用接口尸诽。
使用組合甥材,子類就不需要關(guān)注基類是如何實現(xiàn)的了,基類修改實現(xiàn)細(xì)節(jié)性含,增加公開方法洲赵,也不會影響到子類了。
多態(tài)性
父類或者接口的引用指向或者接收自己的子類對象叫多態(tài) 商蕴。實際執(zhí)行調(diào)用的是子類實現(xiàn)叠萍,這叫動態(tài)綁定。
作用:多態(tài)的存在提高了程序的擴展性和后期可維護性.
發(fā)生多態(tài)要有三個前提條件:
- 繼承绪商。多態(tài)發(fā)生一定要子類和父類之間苛谷。
- 覆蓋。子類覆蓋了父類的方法格郁。
- 聲明的變量類型是父類類型腹殿,但實例則指向子類實例独悴。
UML圖簡介
UML是 Unified Modeling Language 的縮寫,即統(tǒng)一標(biāo)準(zhǔn)建模語言锣尉。它集成了各種優(yōu)秀的建模方法學(xué)發(fā)展而來的刻炒。UML 圖常用的有例圖、協(xié)作圖自沧、活動圖坟奥、序列圖、部署圖拇厢、構(gòu)件圖爱谁、類圖、狀態(tài)圖孝偎。
面向?qū)ο蠓治雠c設(shè)計(OOAD)時管行,會用到 UML 圖,其中類圖非常重要邪媳,用來描述系統(tǒng)靜態(tài)結(jié)構(gòu)捐顷。Student 繼承 Person的類圖如圖所示。類圖中的各個元素說明如圖所示雨效,類用矩形表示迅涮,一般分為上、中徽龟、下三個部分叮姑,上部分是類名,中部分是成員變量据悔,下部分是成員方法传透。實線+空心箭頭表示繼承關(guān)系,箭頭指向父類极颓,箭頭末端是子類朱盐。UML 類圖中還有很多關(guān)系,如圖所示菠隆,如圖虛線+空心箭頭表示實線關(guān)系兵琳,箭頭指向接口,箭頭末端是實線類骇径。
參考
丁振凡編著,《Java 語言程序設(shè)計(第2版)》華東交大版,2014.9
Java 編程的邏輯-微信讀書
https://weread.qq.com/web/reader/b51320f05e159eb51b29226kc81322c012c81e728d9d180