高內(nèi)聚和低耦合
面向?qū)ο蟮淖罱K目的是要構(gòu)建強健州弟、安全钧栖、高效的項目,也就是要實現(xiàn)項目的高內(nèi)聚和低耦合:
高內(nèi)聚:把該模塊的內(nèi)部數(shù)據(jù)呆馁,功能細節(jié)隱藏在模塊內(nèi)部桐经,不允許外界直接干預(yù)毁兆;只能通過公開的接口訪問浙滤;
低耦合:該模塊只需要給外界暴露少量功能方法;模塊之間相互依賴的程度不高气堕;
封裝
什么是封裝
1. 把對象的狀態(tài)和行為看成一個統(tǒng)一的整體纺腊,將二者存放在一個獨立的模塊中,比如:類茎芭;
2. 細節(jié)隱藏, 把不想對外公開的實現(xiàn)細節(jié)隱藏起來揖膜,使用private私有化使其私有化,向外暴露public方法梅桩,保證調(diào)用者安全訪問壹粟,不會出現(xiàn)因為越界導(dǎo)致本不應(yīng)該出現(xiàn)的問題出現(xiàn);
封裝的好處:
1. 調(diào)用者能夠正確、方便地使用系統(tǒng)功能趁仙,有效地防止調(diào)用者隨意修改系統(tǒng)屬性洪添。
2. 把特定的功能封裝起來,提高功能的重用性雀费。
3. 降低功能組件之間的耦合性干奢,即使一個模塊的實現(xiàn)細節(jié)發(fā)生改變,只要保證對外暴露的接口或者方法保持不變盏袄,就不會影響到其他調(diào)用者忿峻。
訪問權(quán)限修飾符
應(yīng)封裝的隱藏細節(jié)的理念,java提供了訪問權(quán)限修飾符來控制調(diào)用者的訪問權(quán)限辕羽,詳情如下:
private:屬于類訪問權(quán)限逛尚,表示私有的,只能在當前類中訪問刁愿,使用private修飾的類黑低、方法、字段酌毡,在’離開當前類的作用域之后克握,調(diào)用者就不能直接訪問。
(缺省):其實就是什么都不寫枷踏,其屬于包訪問權(quán)限菩暗,表示包私有的,調(diào)用者的包必須和當前類(使用缺省修飾)的包相同才能訪問旭蠕。
protected:屬于子類訪問權(quán)限停团,表示受保護的,使用private修飾的類掏熬、方法佑稠、字段,不僅同包中類可以訪問旗芬,而且即使不同包舌胶,但是如果有繼承關(guān)系,也可以訪問疮丛。
public:表示全局的公共訪問權(quán)限幔嫂,使用private修飾的類、方法誊薄、字段履恩,在當前項目中任何地方都可以訪問。接口(interface)中的方法默認都是public的呢蔫。
一般情況下切心,類的字段都使用private修飾;封裝了實現(xiàn)細節(jié)的方法,一般也使用private修飾绽昏,因為不希望調(diào)用者直接訪問其實現(xiàn)細節(jié)扬霜,而是要通過公開的public方法間接調(diào)用。
很少會使用(缺省)而涉,即使要使用著瓶,也僅僅是暴露給同包中的其他類訪問;protected很多時候出現(xiàn)在繼承關(guān)系中啼县,父類只希望被子類訪問的字段和方法時材原;
Java 中的繼承
從面向?qū)ο蟮慕嵌壬险f,繼承是一種從一般到特殊的關(guān)系季眷,是一種“is a”的關(guān)系余蟹,即子類是對父類的拓展,是一種特殊的父類子刮,比如:狗是動物的一種特殊情況威酒,狗屬于動物;在這個例子中挺峡,動物是父類葵孤,狗是子類,狗繼承了動物的特征和行為橱赠,并在動物的特征和行為的基礎(chǔ)之上拓展自己的特征和行為尤仍,構(gòu)成了狗這種特殊的動物。
所以可以基于父類并對其加以拓展狭姨,產(chǎn)生新的子類定義宰啦,這就是繼承;子類可以通過繼承獲得父類原有的字段和方法饼拍,也可以增加父類所沒有的字段和方法赡模,更是可以覆寫父類中的允許被子類覆蓋的字段或者方法。
在Java中使用”extends”關(guān)鍵字來表示子類和父類之間的繼承關(guān)系师抄;在Java中漓柑,類之間的繼承關(guān)系只允許單繼承,不允許多繼承司澎,一個類只能有一個直接父類欺缘。
語法格式:
也就是說一個類只能有一個直接的父類栋豫,不能出現(xiàn)類A同時繼承于類B和類C挤安。即便不允許多繼承,但是多重繼承是被允許的丧鸯。以下是一個多重繼承的例子:
動物有胎生動物和卵生動物之分蛤铜,胎生動物有老虎,老虎又分華南虎,東北虎围肥,孟加拉虎等剿干。在繼承體系中可以這樣來表示:
華南虎——》老虎——》胎生動物——》動物
最終,華南虎通過多重繼承獲得了老虎穆刻、胎生動物置尔、動物的特征和行為。
繼承的優(yōu)點:
1. 有效的解決了代碼的重用問題氢伟,使代碼拓展更加靈活榜轿;
2. 通過從繼承關(guān)系,可以從始至終完整的體現(xiàn)出一個應(yīng)用體系朵锣,邏輯更加清晰谬盐;
3. 一般在開發(fā)中是先有多個自定義類,再從多個類中寫共同的代碼诚些,抽象生成一個父類飞傀,然后子類都繼承于它。使用web框架開發(fā)時诬烹,也會更多的使用繼承來拓展框架的功能砸烦,以適應(yīng)不同的業(yè)務(wù)需求。
子類可以繼承父類的哪些成員(根據(jù)訪問修飾符來判斷):
1. 父類中使用protected绞吁、public修飾的成員外冀;
2. 父類和子類在同一個包中,父類中缺省修飾符的成員可以被子類繼承;
不能繼承的是:
1. 父類中使用private修飾的成員;
2. 父類的構(gòu)造器莲蜘,子類也不能繼承碗暗,因為構(gòu)造器必須和當前的類名相同,父類的構(gòu)造器是父類的名稱徘钥,子類的構(gòu)造器是子類的名稱;
方法重寫和方法重載
方法重寫(Override):從父類繼承的方法(行為)不符合子類的功能需求,那此時子類就需要重新實現(xiàn)父類的方法庄拇,并重寫方法體,以實現(xiàn)子類需求韭邓。
方法重寫的原則:一同兩小一大
一同:方法簽名必須相同措近。 方法簽名= 方法名 + 方法的參數(shù)列表,參數(shù)類型女淑、參數(shù)個數(shù)瞭郑、參數(shù)順序都必須一致
兩小:
1. 子類方法的返回值類型和父類方法的返回類型相同或者是其子類,子類可以返回一個更加具體的子類.
2. 子類方法聲明拋出的異常類型和父類方法聲明拋出的異常類型相同或者是其子類鸭你,子類方法中聲明拋出的異常小于或等于父類方法聲明拋出異常類型屈张;子類方法可以同時聲明拋出多個屬于父類方法聲明拋出異常類的子類(RuntimeException類型除外擒权,RuntimeException是個特例);
一大:子類方法的訪問權(quán)限與父類方法訪問權(quán)限相同或者更大阁谆;而private方法不能被子類所繼承碳抄,也就不會被覆蓋。
在重寫方法父類方法時场绿,使用@Override注解修飾方法剖效,若是重寫錯誤,就會報編譯錯誤焰盗,是一大開發(fā)利器贱鄙;這里需要注意的是只有方法會被重寫,字段則沒有重寫一說姨谷。
方法重載(Overload): 在同一個類中逗宁,方法名字相同,但是因方法參數(shù)列表不同而又不同的實現(xiàn)梦湘,這樣的機制稱為方法重載瞎颗,其實現(xiàn)原則是:兩同一不同,返回值并不計入其中捌议。
兩同:相同類哼拔,方法名(只是方法名,不是方法簽名)相同
一不同:方法參數(shù)列表不同瓣颅,包括參數(shù)類型倦逐、參數(shù)個數(shù)、參數(shù)順序都必須一致
方法重載(Overload)和方法重寫(Override)兩者只是名字上比較接近宫补,其本身并沒有關(guān)系檬姥。
this 關(guān)鍵字
this關(guān)鍵字表示當前對象,當前對象就是this所在的這個對象粉怕。this主要存在于兩個位置:
1. 構(gòu)造器中:就表示當前正在創(chuàng)建的對象
2. 方法中:表示方法的調(diào)用者對象
當一個對象創(chuàng)建之后健民,JVM會為對象分配一個引用該對象自身的引用:this。this的使用是為了:
1. 解決成員變量和方法參數(shù)贫贝、局部變量之間的二義性秉犹,使用this可以顯式指向成員變量;
2. 同類中實例方法間相互調(diào)用,雖然此時可以省略不寫稚晚,但還是建議不要省略崇堵,以提高代碼的可讀性。
3. 將this作為參數(shù)傳遞給另一個方法;
4. 將this作為方法的返回值(鏈式方法編程);
5. 構(gòu)造器重載的互相調(diào)用客燕,this([參數(shù)])必須寫在構(gòu)造方法第一行;
6. static不能和this一起使用;因為當字節(jié)碼被加載進JVM的時候鸳劳,static成員就已經(jīng)存在了,但是此時對象很有可能還沒有被創(chuàng)建幸逆,沒有對象也就沒有this棍辕。
super 關(guān)鍵字
在對象中this表示當前對象暮现,而super則表示當前對象的父類對象还绘。在子類初始化過程中會創(chuàng)建子類對象楚昭,但在創(chuàng)建子類對象之前,會先創(chuàng)建父類對象拍顷;也就是說調(diào)用子類構(gòu)造器之前,在子類構(gòu)造器中會先調(diào)用父類的構(gòu)造器抚太,如果沒有顯式的調(diào)用父類構(gòu)造器,那么默認情況下會隱式的調(diào)用父類無參數(shù)構(gòu)造器昔案。
super關(guān)鍵字用于顯式調(diào)用父類方法尿贫、構(gòu)造器和字段;可以使用super解決子類隱藏了父類的字段情況踏揣;在子類方法中庆亡,調(diào)用父類被覆蓋的方法;在子類構(gòu)造器中捞稿,調(diào)用父類構(gòu)造器又谋。
父類構(gòu)造器的不可或缺性:
1. 如果父類不存在可以被子類訪問/調(diào)用的構(gòu)造器,則子類就不可能存在娱局。也就是必須要先有父類對象彰亥,而后才會有子類對象;
2. 如果父類沒有提供無參數(shù)構(gòu)造器衰齐,子類就必須顯式地通過super語句去調(diào)用父類帶參數(shù)的構(gòu)造器任斋。子類對象在初始化過程中,必須先調(diào)用父類構(gòu)造器耻涛,而后再調(diào)用子類構(gòu)造器废酷。
繼承中的隱藏
上文中提到了隱藏的概念,繼承中的隱藏表示會忽略一些特征和方法抹缕,比如靜態(tài)字段和靜態(tài)方法:
1. 滿足繼承的訪問權(quán)限下锦积,隱藏父類靜態(tài)方法:若子類定義的靜態(tài)方法的簽名和超類中的靜態(tài)方法簽名相同,那么此時就是隱藏父類方法歉嗓。注意:僅僅是在子類存在和父類一模一樣的靜態(tài)方法的情況下丰介。
2. 滿足繼承的訪問權(quán)限下,隱藏父類字段:若子類中定義的字段和父類中的字段名相同(忽略數(shù)據(jù)類型)鉴分,此時是隱藏父類字段哮幢,但是可以通過super訪問被隱藏的字段。
3. 隱藏本類字段:若本類中的局部變量名和字段名相同志珍,此時就是隱藏本類字段橙垢,可以通過this訪問被隱藏的字段。
無論是this伦糯,還是super柜某,都不能和static一起使用嗽元。
Object 類
在Java中除去Object類之外的每一個類都有一個直接或間接的父類:Object類。也就是說除去Object類之外的類都是Object類的直接子類或間接子類喂击。
比如:
此時Student類的直接父類是Person剂癌,Person類的直接父類是Object類,Object類是Student類的間接父類翰绊。
Object類是Java的基類佩谷,Java中的類都是Object的直接或者間接的子類,Object本身是指對象的意思, 它是所有的對象都具有的共同的行為的抽象類监嗜,其他類都會直接或者間接繼承于Object類谐檀,然后也就擁有了Object類中的方法。
Object類的常見方法:
finalize() :當垃圾回收器確定不存在對該對象的更多引用時裁奇,也就是垃圾回收器會在回收對象之前桐猬,會先調(diào)用該方法;該方法我們一般不會調(diào)用刽肠。
getClass() :返回當前對象的真實類型溃肪。
hashCode():返回該對象的哈希碼值,hashCode(哈希碼值)決定了對象再哈希表中的存儲位置五垮,不同對象的存儲位置是不一樣的乍惊,所以hashCode也會是不一樣的。
equals(Object obj) :用當前對象(this)和參數(shù)obj做比較放仗,在Object類中的equals方法润绎,比較對象的內(nèi)存地址。官方建議:每個類都應(yīng)該覆蓋equals方法诞挨,不要比較內(nèi)存地址莉撇,而是去比較內(nèi)容數(shù)據(jù)。
toString():表示把一個對象轉(zhuǎn)換為字符串惶傻,打印對象時棍郎,調(diào)用的就是對象的toString方法,默認情況下打印的是對象的十六進制的hashCode值银室。 官方建議:應(yīng)該每個類都應(yīng)該覆蓋toString涂佃,返回我們真正關(guān)心的數(shù)據(jù)。
多態(tài)
通過上文蜈敢,講清楚了繼承關(guān)系辜荠,繼承關(guān)系是一種”is a”(是一種)的關(guān)系,也就是說子類是父類的一種特殊情況抓狭;既然子類是一種特殊的父類伯病,我們是否可以認為子類對象就是父類類型的對象。
考慮以下的代碼:
這個時候否过,多態(tài)就產(chǎn)生了午笛。我們以下面的代碼為例惭蟋,詳細解釋什么是多態(tài):
在上例中,對象a具有兩種類型:
1. 編譯類型:聲明對象變量的類型药磺,Animal告组;表示把對象看作是什么類型。
2. 運行類型:對象的真實類型与涡,Dog惹谐;運行類型--->對象的真實類型持偏。
編譯類型必須是運行類型的父類或與之相同驼卖,當編譯類型和運行類型不同的時候,多態(tài)就產(chǎn)生了鸿秆。所謂多態(tài)是指對象具有多種形態(tài)酌畜,對象可以存在不同的形式:
多態(tài)可以是類和類之間的繼承關(guān)系,也可以是接口和實現(xiàn)類間的實現(xiàn)關(guān)系卿叽,一般情況下指的都是接口和實現(xiàn)類間的實現(xiàn)關(guān)系桥胞。
多態(tài)的特點:把子類對象賦給父類類型的變量,在運行時期會表現(xiàn)出具體的子類特征考婴,比如父類類型的變量調(diào)用子類的方法贩虾。
多態(tài)的好處:(通過一個例子呈現(xiàn))
需求:給飼養(yǎng)員提供一個喂養(yǎng)動物的方法,用于喂養(yǎng)動物。
如果沒有多態(tài)沥阱,針對于不同類型的動物缎罢,得提供不同的喂養(yǎng)方法】忌迹可拓展性差策精,方法重用性低,不優(yōu)雅崇棠。
存在多態(tài):提供統(tǒng)一的喂養(yǎng)方法咽袜,大大減輕了飼養(yǎng)員的工作量。從上述例子枕稀,不難發(fā)現(xiàn):當把不同的子類對象都當作父類類型來看待询刹,可以屏蔽不同子類對象之間的實現(xiàn)差異,從而寫出通用的代碼達到通用編程萎坷,以適應(yīng)需求的不斷變化凹联。
數(shù)據(jù)類型轉(zhuǎn)換
基本數(shù)據(jù)類型轉(zhuǎn)換:大和小表示的是可存儲的容量范圍。
自動類型轉(zhuǎn)換:把小類型的數(shù)據(jù)賦給大類型的變量:
byte b = 12; byte是1個字節(jié)
int i = b; int是4個字節(jié)
強制類型轉(zhuǎn)換:把大類型的數(shù)據(jù)賦給小類型的變量食铐。
short s = (short) i ;short是2個字節(jié)
引用類型的轉(zhuǎn)換:?引用類型的大和小,指的是父類和子類的關(guān)系匕垫。
自動類型轉(zhuǎn)換:?把子類對象賦給父類變量(多態(tài))。
強制類型轉(zhuǎn)換:把父類類型對象賦給子類類型變量(對象的真實類型是子類類型)虐呻。
instanceof 運算符
instanceof 運算符: 判斷該對象是否是某一個類的實例象泵。
1. 若對象是類的實例返回true寞秃。
2. 若對象是類的父類的實例也返回true。
語法格式:
組合關(guān)系(has a)
在繼承關(guān)系中偶惠,子類可以繼承到父類中部分的成員春寿,那么此時子類是可以修改到父類的信息的,此時的繼承關(guān)系破壞了封裝忽孽,讓子類擁有了本不該具有的功能绑改。那么這時可以使用”包含關(guān)系”(has a)的組合關(guān)系。
可以這么理解組合關(guān)系:把另一個類當作屬性來獲取其特征和行為兄一。
比如:需求是:我想擁有天子的權(quán)力;
方式1:當太子厘线,此時表現(xiàn)的是繼承關(guān)系;
方式2:學(xué)曹操挾天子以令諸侯出革,挾持天子造壮,此時是組合/包含關(guān)系。
思考:如果A類想要得到B的功能行為骂束,如若A類是B類的一種特殊情況耳璧,就應(yīng)該采用繼承來實現(xiàn),否則使用組合方式展箱。
完結(jié)旨枯。老夫雖不正經(jīng),但老夫一身的才華