摘要:抽象數(shù)據(jù)類型的多個(gè)不同表示可以共存于同一個(gè)程序中,作為實(shí)現(xiàn)接口的不同類。封裝和信息隱藏信息隱藏將精心設(shè)計(jì)的模塊與不好的模塊區(qū)分開(kāi)來(lái)的唯一最重要的因素是其隱藏內(nèi)部數(shù)據(jù)和其他模塊的其他實(shí)施細(xì)節(jié)的程度。
大綱
面向?qū)ο蟮臉?biāo)準(zhǔn)
基本概念:對(duì)象,類,屬性,方法和接口
OOP的獨(dú)特功能
封裝和信息隱藏 繼承和重寫 多態(tài)性,子類型和重載 靜態(tài)與動(dòng)態(tài)分派
Java中一些重要的Object方法
設(shè)計(jì)好的類
面向?qū)ο蟮臍v史
總結(jié)
面向?qū)ο蟮木幊谭椒?語(yǔ)言應(yīng)該具有類的概念作為中心概念。
語(yǔ)言應(yīng)該能夠?yàn)轭惡退奶卣魈峁嘌裕匆?guī)范:前置條件,后置條件和不變量)和異常處理,依靠工具生成這些斷言中的文檔,并且可選地在運(yùn)行時(shí)監(jiān)視它們 時(shí)間。
他們幫助生產(chǎn)可靠的軟件;
他們提供系統(tǒng)文件;
它們是測(cè)試和調(diào)試面向?qū)ο筌浖暮诵墓ぞ摺?/p>
靜態(tài)類型:一個(gè)定義良好的類型系統(tǒng)應(yīng)該通過(guò)強(qiáng)制執(zhí)行一些類型聲明和兼容性規(guī)則來(lái)保證它接受的系統(tǒng)的運(yùn)行時(shí)類型安全。
泛型(Genericity):用于“準(zhǔn)備改變”和“為/重用設(shè)計(jì)”:應(yīng)該可以編寫具有表示任意類型的正式泛型參數(shù)的類。
繼承(Inheritance):應(yīng)該可以將一個(gè)類定義為從另一個(gè)繼承,以控制潛在的復(fù)雜性。
多態(tài)(Polymorphism):在基于繼承的類型系統(tǒng)的控制下,應(yīng)該可以將實(shí)體(表示運(yùn)行時(shí)對(duì)象的軟件文本中的名稱)附加到各種可能類型的運(yùn)行時(shí)對(duì)象。
動(dòng)態(tài)分派/綁定(Dynamic dispatch / binding):在一個(gè)實(shí)體上調(diào)用一個(gè)特性應(yīng)該總是觸發(fā)與所附加的運(yùn)行時(shí)對(duì)象的類型相對(duì)應(yīng)的特性,這在調(diào)用的不同執(zhí)行過(guò)程中不一定是相同的。
基本概念:對(duì)象,類,屬性和方法對(duì)象
真實(shí)世界的物體有兩個(gè)特征:它們都有狀態(tài)和行為。
識(shí)別真實(shí)世界對(duì)象的狀態(tài)和行為是從OOP角度開(kāi)始思考的好方法。
狗有狀態(tài)(名稱,顏色,品種,饑餓)和行為(吠叫,取出,搖尾巴)。
自行車具有狀態(tài)(當(dāng)前檔位,當(dāng)前踏板節(jié)奏,當(dāng)前速度)和行為(更換檔位,改變踏板節(jié)奏,應(yīng)用制動(dòng)器)。
對(duì)于你看到的每個(gè)對(duì)象,問(wèn)自己兩個(gè)問(wèn)題,這些現(xiàn)實(shí)世界的觀察都轉(zhuǎn)化為OOP的世界:
這個(gè)物體有什么可能的狀態(tài)?
這個(gè)對(duì)象有什么可能的行為?
一個(gè)對(duì)象是一組狀態(tài)和行為
狀態(tài) - 包含在對(duì)象中的數(shù)據(jù)。
在Java中,這些是對(duì)象的字段
行為 - 對(duì)象支持的操作
在Java中,這些被稱為方法
方法只是面向?qū)ο蟮墓δ?/p>
調(diào)用一個(gè)方法=調(diào)用一個(gè)函數(shù)
類
每個(gè)對(duì)象都有一個(gè)類
一個(gè)類定義方法和字段
統(tǒng)稱為成員的方法和領(lǐng)域
類定義了類型和實(shí)現(xiàn)
類型≈可以使用對(duì)象的位置
執(zhí)行≈對(duì)象如何做事情
松散地說(shuō),類的方法是它的應(yīng)用程序編程接口(API)
定義用戶如何與實(shí)例進(jìn)行交互
靜態(tài)與實(shí)例變量/類的方法
類成員變量:與類相關(guān)聯(lián)的變量,而不是類的實(shí)例。 您還可以將方法與類關(guān)聯(lián) - 類方法。
要引用類變量和方法,需要將類的名稱和類方法或類變量的名稱連同句點(diǎn)(".")一起加入。
不是類方法或類變量的方法和變量稱為實(shí)例方法和實(shí)例成員變量。
要引用實(shí)例方法和變量,必須引用類實(shí)例中的方法和變量
總結(jié):
類變量和類方法與類相關(guān)聯(lián),并且每個(gè)類都會(huì)出現(xiàn)一次。 使用它們不需要?jiǎng)?chuàng)建對(duì)象。
實(shí)例方法和變量在類的每個(gè)實(shí)例中出現(xiàn)一次。
靜態(tài)方法不與任何特定的類實(shí)例關(guān)聯(lián),而實(shí)例方法(不帶static關(guān)鍵字聲明)必須在特定對(duì)象上調(diào)用。
接口Java的接口是一種用于設(shè)計(jì)和表達(dá)ADT的有用語(yǔ)言機(jī)制,其實(shí)現(xiàn)方式是實(shí)現(xiàn)該接口的類。
Java中的接口是方法簽名的列表,但沒(méi)有方法體。
如果一個(gè)類在其implements子句中聲明接口并為所有接口的方法提供方法體,則該類將實(shí)現(xiàn)一個(gè)接口。
一個(gè)接口可以擴(kuò)展一個(gè)或多個(gè)其他接口
一個(gè)類可以實(shí)現(xiàn)多個(gè)接口
接口和類:定義和實(shí)現(xiàn)ADT
接口之間可以繼承
一個(gè)類可以實(shí)現(xiàn)多個(gè)接口
接口和實(shí)現(xiàn)
API的多個(gè)實(shí)現(xiàn)可以共存
多個(gè)類可以實(shí)現(xiàn)相同的API
他們?cè)谛阅芎托袨榉矫婵赡苡兴煌?/p>
在Java中,API由接口或類指定
接口只提供一個(gè)API
一個(gè)接口定義但不實(shí)現(xiàn)API
類提供了一個(gè)API和一個(gè)實(shí)現(xiàn)
一個(gè)類可以實(shí)現(xiàn)多個(gè)接口
一個(gè)接口可以有多種實(shí)現(xiàn)
Java接口和類
接口與類
接口:確定ADT規(guī)約
類:實(shí)現(xiàn)ADT
類確實(shí)定義了類型
類似接口方法的公共類方法
可從其他課程直接訪問(wèn)的公共字段
但更喜歡使用接口
除非你知道一個(gè)實(shí)現(xiàn)就足夠,否則使用變量和參數(shù)的接口類型。
支持更改實(shí)施;
防止依賴于實(shí)施細(xì)節(jié)
問(wèn)題:打破抽象邊界
客戶必須知道具體表示類的名稱。
因?yàn)镴ava中的接口不能包含構(gòu)造函數(shù),所以它們必須直接調(diào)用其中一個(gè)具體類的構(gòu)造函數(shù)。
構(gòu)造函數(shù)的規(guī)范不會(huì)出現(xiàn)在接口的任何位置,所以沒(méi)有任何靜態(tài)的保證,即使不同的實(shí)現(xiàn)甚至?xí)峁┫嗤臉?gòu)造函數(shù)。
接口的優(yōu)點(diǎn)
接口指定了客戶端的契約,僅此而已。
接口是客戶程序員需要閱讀才能理解ADT的全部?jī)?nèi)容。
客戶端不能在ADT的表示上創(chuàng)建無(wú)意的依賴關(guān)系,因?yàn)閷?shí)例變量根本無(wú)法放入接口。
實(shí)現(xiàn)完全保持完全分離,完全不同。 抽象數(shù)據(jù)類型的多個(gè)不同表示可以共存于同一個(gè)程序中,作為實(shí)現(xiàn)接口的不同類。
當(dāng)一個(gè)抽象數(shù)據(jù)類型被表示為一個(gè)多帶帶的類時(shí),如果沒(méi)有接口,就很難擁有多個(gè)表示。
為什么有多個(gè)實(shí)現(xiàn)
不同的表現(xiàn)
選擇最適合您使用的實(shí)現(xiàn)
不同的行為
選擇你想要的實(shí)現(xiàn)
行為必須符合接口規(guī)范(“契約”)
性能和行為往往不盡相同
提供功能
性能權(quán)衡
示例:HashSet,TreeSet
接口總結(jié)
編譯器和人員的文檔
允許性能權(quán)衡
可選的方法
有意識(shí)欠定規(guī)格的方法
一個(gè)類的多個(gè)視圖
越來(lái)越不值得信賴的實(shí)現(xiàn)
減少錯(cuò)誤保證安全
ADT由它的操作定義,而接口就是這樣做的。
當(dāng)客戶端使用接口類型時(shí),靜態(tài)檢查確保它們只使用接口定義的方法。
如果實(shí)現(xiàn)類暴露其他方法 - 或更糟糕的是,具有可見(jiàn)的表示 - 客戶端不會(huì)意外地看到或依賴它們。
當(dāng)我們有一個(gè)數(shù)據(jù)類型的多個(gè)實(shí)現(xiàn)時(shí),接口提供方法簽名的靜態(tài)檢查。
容易明白
客戶和維護(hù)人員確切知道在哪里查找ADT的規(guī)范。
由于接口不包含實(shí)例字段或?qū)嵗椒ǖ膶?shí)現(xiàn),因此更容易將實(shí)現(xiàn)的細(xì)節(jié)保留在規(guī)范之外。
準(zhǔn)備好改變
我們可以通過(guò)添加實(shí)現(xiàn)接口的類輕松地添加新類型的實(shí)現(xiàn)。
如果我們避免使用靜態(tài)工廠方法的構(gòu)造函數(shù),客戶端將只能看到該接口。
這意味著我們可以切換客戶端正在使用的實(shí)現(xiàn)類,而無(wú)需更改其代碼。
封裝和信息隱藏信息隱藏
將精心設(shè)計(jì)的模塊與不好的模塊區(qū)分開(kāi)來(lái)的唯一最重要的因素是其隱藏內(nèi)部數(shù)據(jù)和其他模塊的其他實(shí)施細(xì)節(jié)的程度。
設(shè)計(jì)良好的代碼隱藏了所有的實(shí)現(xiàn)細(xì)節(jié)
將API與實(shí)施完全分開(kāi)
模塊只通過(guò)API進(jìn)行通信
對(duì)彼此的內(nèi)在運(yùn)作無(wú)知
被稱為信息隱藏或封裝,是軟件設(shè)計(jì)的基本原則。
信息隱藏的好處
將構(gòu)成系統(tǒng)的類分開(kāi)
允許它們獨(dú)立開(kāi)發(fā),測(cè)試,優(yōu)化,使用,理解和修改
加速系統(tǒng)開(kāi)發(fā)
類可以并行開(kāi)發(fā)
減輕了維護(hù)的負(fù)擔(dān)
可以更快速地理解類并調(diào)試,而不必害怕?lián)p害其他模塊
啟用有效的性能調(diào)整
“熱”類可以多帶帶優(yōu)化
增加軟件重用
松散耦合的類通常在其他情況下證明是有用的
通過(guò)接口隱藏信息
使用接口類型聲明變量
客戶端只能使用接口方法
客戶端代碼無(wú)法訪問(wèn)的字段
但我們到目前為止
客戶端可以直接訪問(wèn)非接口成員
實(shí)質(zhì)上,它是自愿的信息隱藏
成員的可見(jiàn)性修飾符
private - 只能從聲明類訪問(wèn)
protected - 可以從聲明類的子類(以及包內(nèi))
public - 從任何地方訪問(wèn)
信息隱藏的最佳實(shí)踐
仔細(xì)設(shè)計(jì)你的API
只提供客戶需要的功能,其他所有成員應(yīng)該是私人的
您可以隨時(shí)在不破壞客戶的情況下讓私人成員公開(kāi)
但反之亦然!
繼承和重寫(1)重寫
可重寫的方法和嚴(yán)格的繼承
可重寫方法:允許重新實(shí)現(xiàn)的方法。
在Java方法中默認(rèn)是可重寫的,即沒(méi)有特殊的關(guān)鍵字。
嚴(yán)格的繼承
子類只能向超類添加新的方法,它不能覆蓋它們
如果某個(gè)方法不能在Java程序中被覆蓋,則必須以關(guān)鍵字final為前綴。
final
final字段:防止初始化后重新分配給字段
final方法:防止重寫該方法
final類:阻止繼承類
重寫
方法重寫是一種語(yǔ)言功能,它允許子類或子類提供已由其超類或父類之一提供的方法的特定實(shí)現(xiàn)。
相同的名稱,相同的參數(shù)或簽名,以及相同的返回類型。
執(zhí)行的方法的版本將由用于調(diào)用它的對(duì)象決定。實(shí)際執(zhí)行時(shí)調(diào)用哪個(gè)方法,運(yùn)行時(shí)決定。
如果父類的對(duì)象用于調(diào)用該方法,則會(huì)執(zhí)行父類中的版本;
如果使用子類的對(duì)象來(lái)調(diào)用該方法,則會(huì)執(zhí)行子類中的版本。
當(dāng)子類包含一個(gè)覆蓋超類方法的方法時(shí),它也可以使用關(guān)鍵字super調(diào)用超類方法。
重寫的時(shí)候,不要改變?cè)椒ǖ谋疽?/p>
(2)抽象類
抽象方法和抽象類
抽象方法:
具有簽名但沒(méi)有實(shí)現(xiàn)的方法(也稱為抽象操作)
由關(guān)鍵字abstract定義
抽象類:
一個(gè)包含至少一個(gè)抽象方法的類被稱為抽象類
接口:只有抽象方法的抽象類
接口主要用于系統(tǒng)或子系統(tǒng)的規(guī)范。 該實(shí)現(xiàn)由子類或其他機(jī)制提供。
具體類?抽象類?接口
多態(tài)性,子類型和重載(1)三種多態(tài)性
特殊多態(tài)(Ad hoc polymorphism):當(dāng)一個(gè)函數(shù)表示不同且可能不同種類的實(shí)現(xiàn)時(shí),取決于多帶帶指定類型和組合的有限范圍。 使用函數(shù)重載(function overloading)在許多語(yǔ)言中支持特設(shè)多態(tài)。
參數(shù)化多態(tài)(parametric polymorphism):當(dāng)代碼被寫入時(shí)沒(méi)有提及任何特定類型,因此可以透明地使用任何數(shù)量的新類型。 在面向?qū)ο蟮木幊躺鐓^(qū)中,這通常被稱為泛型或泛型編程。
子類型多態(tài)(也稱為子類型多態(tài)或包含多態(tài)):當(dāng)名稱表示由一些公共超類相關(guān)的許多不同類的實(shí)例。
(2)特殊多態(tài)和重載
當(dāng)函數(shù)適用于幾種不同的類型(可能不會(huì)顯示公共結(jié)構(gòu))并且可能以不相關(guān)的方式表現(xiàn)每種類型時(shí),可以獲得特殊多態(tài)。
(3)重載
重載的方法允許您在類中重復(fù)使用相同的方法名稱,但使用不同的參數(shù)(以及可選的不同的返回類型)。
重載方法通常意味著對(duì)于那些調(diào)用方法的人來(lái)說(shuō)會(huì)更好一些,因?yàn)榇a承擔(dān)了應(yīng)對(duì)不同參數(shù)類型的負(fù)擔(dān),而不是在調(diào)用方法之前強(qiáng)制調(diào)用方執(zhí)行轉(zhuǎn)換。
函數(shù)重載可以在不同的實(shí)現(xiàn)中創(chuàng)建同名的多個(gè)方法。
對(duì)重載函數(shù)的調(diào)用將運(yùn)行適合于調(diào)用上下文的該函數(shù)的特定實(shí)現(xiàn),允許一個(gè)函數(shù)調(diào)用根據(jù)上下文執(zhí)行不同的任務(wù)。
重載是一種靜態(tài)多態(tài)
函數(shù)調(diào)用使用“最佳匹配技術(shù)”解決,即根據(jù)參數(shù)列表解析函數(shù)。
函數(shù)調(diào)用中的靜態(tài)類型檢查
在編譯時(shí)確定使用這些方法中的哪一個(gè)。(靜態(tài)類型檢查)
與之相反,重寫方法則是在運(yùn)行時(shí)進(jìn)行動(dòng)態(tài)檢查!
重載規(guī)則
函數(shù)重載中的規(guī)則:重載函數(shù)必須因參數(shù)或數(shù)據(jù)類型而有所不同
必須改變參數(shù)列表。
可以改變返回類型。
可以改變?cè)L問(wèn)修飾符。
可以聲明新的或更廣泛的檢查異常。
一個(gè)方法可以在同一個(gè)類或子類中重載。
重寫與重載
不要混淆覆蓋派生類中的方法和重載方法名稱
當(dāng)方法被覆蓋時(shí),派生類中給出的新方法定義與基類中的參數(shù)數(shù)量和類型完全相同
當(dāng)派生類中的方法與基類中的方法有不同的簽名時(shí),即重載
請(qǐng)注意,當(dāng)派生類重載原始方法時(shí),它仍然繼承基類中的原始方法
(3)參數(shù)多態(tài)性和泛型編程
當(dāng)一個(gè)函數(shù)在一系列類型上統(tǒng)一工作時(shí)獲得參數(shù)多態(tài)性; 這些類型通常具有一些共同的結(jié)構(gòu)。
它能夠以通用的方式定義函數(shù)和類型,以便它可以在運(yùn)行時(shí)傳遞參數(shù)的基礎(chǔ)上工作,即允許在沒(méi)有完全指定類型的情況下進(jìn)行靜態(tài)類型檢查。
這是Java中所謂的“泛型(Generic)”。
泛型編程是一種編程風(fēng)格,其中數(shù)據(jù)類型和函數(shù)是根據(jù)待指定的類型編寫的,隨后在需要時(shí)作為參數(shù)提供的特定類型實(shí)例化。
泛型編程圍繞從具體,高效的算法中抽象出來(lái)以獲得可與不同數(shù)據(jù)表示形式結(jié)合的泛型算法來(lái)生成各種各樣有用軟件的想法相關(guān)。
Java中的泛型
類型變量是一個(gè)不合格的標(biāo)識(shí)符。
它們由泛型類聲明,泛型接口聲明,泛型方法聲明和泛型構(gòu)造函數(shù)聲明引入。
如果一個(gè)類聲明一個(gè)或多個(gè)類型變量,則該類是通用的。
泛型類:其定義中包含了類型變量
這些類型的變量被稱為類的類型參數(shù)。
它定義了一個(gè)或多個(gè)作為參數(shù)的類型變量。
泛型類聲明定義了一組參數(shù)化類型,每個(gè)類型參數(shù)部分的每個(gè)可能的調(diào)用都有一個(gè)類型聲明。
所有這些參數(shù)化類型在運(yùn)行時(shí)共享相同的類。
如果聲明了類型變量,則interface是通用的。
這些類型變量被稱為接口的類型參數(shù)。
它定義了一個(gè)或多個(gè)作為參數(shù)的類型變量。
通用接口聲明定義了一組類型,每種類型參數(shù)部分的每個(gè)可能的調(diào)用都有一個(gè)類型。
所有參數(shù)化類型在運(yùn)行時(shí)共享相同的接口。
如果聲明類型變量,則方法是通用的。
這些類型的變量被稱為方法的形式類型參數(shù)。
形式類型參數(shù)列表的形式與類或接口的類型參數(shù)列表相同。
類型變量
使用菱形運(yùn)算符<>來(lái)幫助聲明類型變量。
一些Java泛型細(xì)節(jié)
可以有多個(gè)類型參數(shù)
例如Map
Wildcards通配符,只在使用泛型的時(shí)候出現(xiàn),不能在定義中出現(xiàn)
List <?> list = new ArrayList
List extends Animal>
List super Animal>
通用類型信息被擦除(即僅編譯時(shí))
不能使用instanceof()來(lái)檢查通用類型運(yùn)行時(shí)泛型消失了!
無(wú)法創(chuàng)建通用數(shù)組
Pair
(4)子類多態(tài)性
子類
一個(gè)類型是一組值。
Java List類型由接口定義。
如果我們考慮所有可能的List值,它們都不是List對(duì)象:我們不能創(chuàng)建接口的實(shí)例。
相反,這些值都是ArrayList對(duì)象或LinkedList對(duì)象,或者是實(shí)現(xiàn)List的另一個(gè)類的對(duì)象。
子類型只是超類型的一個(gè)子集
ArrayList和LinkedList是List的子類型。
繼承/子類型的好處:重用代碼,建模靈活性
在Java中:每個(gè)類只能直接繼承一個(gè)父類; 一個(gè)類可以實(shí)現(xiàn)多個(gè)接口。
“B是A的子類型”意思是“每個(gè)B都是A.”
在規(guī)格方面:“每個(gè)B都符合A的規(guī)格”。
如果B的規(guī)格至少和A的規(guī)格一樣強(qiáng),B只是A的一個(gè)子類型。 - 當(dāng)我們聲明一個(gè)實(shí)現(xiàn)接口的類時(shí),Java編譯器會(huì)自動(dòng)執(zhí)行這個(gè)需求的一部分:它確保A中的每個(gè)方法出現(xiàn)在B中,并帶有一個(gè)兼容的類型簽名。
B類不能實(shí)現(xiàn)接口A,而不實(shí)現(xiàn)A中聲明的所有方法。
靜態(tài)檢查子類型
但編譯器無(wú)法檢查我們是否以其他方式削弱了規(guī)范:
加強(qiáng)對(duì)某種方法的某些投入的先決條件
弱化后置條件
弱化接口抽象類型通告客戶端的保證。
如果你在Java中聲明了一個(gè)子類型(例如,實(shí)現(xiàn)一個(gè)接口),那么你必須確保子類型的規(guī)范至少和超類型一樣強(qiáng)。
子類型的規(guī)約不能弱化超類型的規(guī)約。
子類型多態(tài)
子類型多態(tài):不同類型的對(duì)象可以被客戶代碼統(tǒng)一處理子類型多態(tài):不同類型的對(duì)象可以統(tǒng)一的處理而無(wú)需區(qū)分
每個(gè)對(duì)象根據(jù)其類型行為(例如,如果添加新類型的帳戶,客戶端代碼不會(huì)更改)從而隔離了“變化”
Liskov替換原則(LSP):
如果S是T的子類型,那么類型T的對(duì)象可以用類型S的對(duì)象替換(即,類型T的對(duì)象可以用子類型S的任何對(duì)象代替)而不改變T的任何期望屬性。
instanceof
測(cè)試某個(gè)對(duì)象是否為給定類的運(yùn)算符
建議:如果可能,避免使用instanceof(),并且從不在超類中使用instanceof()來(lái)檢查針對(duì)子類的類型。
類型轉(zhuǎn)換
有時(shí)你想要一種不同于你已有的類型
如果你知道你有一個(gè)更具體的子類型,很有用
但是如果類型不兼容,它會(huì)得到一個(gè)ClassCastException
建議:
避免向下轉(zhuǎn)換類型
從不在超類內(nèi)向某個(gè)子類下降
動(dòng)態(tài)分派動(dòng)態(tài)分派是選擇在運(yùn)行時(shí)調(diào)用多態(tài)操作的哪個(gè)實(shí)現(xiàn)的過(guò)程。
面向?qū)ο蟮南到y(tǒng)將一個(gè)問(wèn)題建模為一組交互對(duì)象,這些對(duì)象執(zhí)行按名稱引用的操作。
多態(tài)現(xiàn)象是這樣一種現(xiàn)象,即有些可互換的對(duì)象每個(gè)都暴露同一名稱的操作,但行為可能不同。
確定在運(yùn)行時(shí)要調(diào)用哪種方法,即對(duì)重寫或多態(tài)方法的調(diào)用可在運(yùn)行時(shí)解決
作為示例,F(xiàn)ile對(duì)象和Database對(duì)象都有一個(gè)StoreRecord方法,可用于將人員記錄寫入存儲(chǔ)。 他們的實(shí)現(xiàn)不同。
一個(gè)程序持有一個(gè)對(duì)象的引用,該對(duì)象可能是一個(gè)File對(duì)象或一個(gè)數(shù)據(jù)庫(kù)對(duì)象。 它可能是由運(yùn)行時(shí)間設(shè)置決定的,在這個(gè)階段,程序可能不知道或關(guān)心哪一個(gè)。
當(dāng)程序在對(duì)象上調(diào)用StoreRecord時(shí),需要確定哪些行為被執(zhí)行。
該程序?qū)toreRecord消息發(fā)送給未知類型的對(duì)象,并將其留給運(yùn)行時(shí)支持系統(tǒng)以將消息分派給正確的對(duì)象。 該對(duì)象實(shí)現(xiàn)它實(shí)現(xiàn)的任何行為。
動(dòng)態(tài)分派與靜態(tài)分派形成對(duì)比,其中在編譯時(shí)選擇多態(tài)操作的實(shí)現(xiàn)。
動(dòng)態(tài)分派的目的是為了支持在編譯時(shí)無(wú)法確定多態(tài)操作的適當(dāng)實(shí)現(xiàn)的情況,因?yàn)樗蕾囉诓僮鞯囊粋€(gè)或多個(gè)實(shí)際參數(shù)的運(yùn)行時(shí)類型。
靜態(tài)分派:編譯階段即可確定要執(zhí)行哪個(gè)具體操作。
重載的方法使用靜態(tài)分派,而重寫的方法在運(yùn)行時(shí)使用動(dòng)態(tài)分派。
動(dòng)態(tài)分派不同于動(dòng)態(tài)綁定(也稱為動(dòng)態(tài)綁定)。
選擇操作時(shí),綁定會(huì)將名稱與操作關(guān)聯(lián)。
在決定了名稱引用的操作后,分派會(huì)為操作選擇一個(gè)實(shí)現(xiàn)。
綁定:將調(diào)用的名字與實(shí)際的方法名字聯(lián)系起來(lái)(可能很多個(gè));
分派:具體執(zhí)行哪個(gè)方法(提前綁定→靜態(tài)分派)
通過(guò)動(dòng)態(tài)分派,該名稱可以在編譯時(shí)綁定到多態(tài)操作,但不會(huì)在運(yùn)行時(shí)間之前選擇實(shí)現(xiàn)。動(dòng)態(tài)分派:編譯階段可能綁定到多態(tài)操作,運(yùn)行階段決定具體執(zhí)行哪個(gè)(覆蓋和過(guò)載均是如此);
雖然動(dòng)態(tài)分派并不意味著動(dòng)態(tài)綁定,但動(dòng)態(tài)綁定確實(shí)意味著動(dòng)態(tài)分派,因?yàn)榻壎Q定了可用分派的集合。
提前/靜態(tài)綁定
每當(dāng)發(fā)生靜態(tài),私有和最終方法的綁定時(shí),類的類型由編譯器在編譯時(shí)確定,并且綁定在那里和那里發(fā)生。
推遲/動(dòng)態(tài)綁定
重寫父類和子類都有相同的方法,在這種情況下,對(duì)象的類型決定了要執(zhí)行哪種方法。 對(duì)象的類型在運(yùn)行時(shí)確定。
動(dòng)態(tài)方法分派
1.(編譯時(shí))確定要查找哪個(gè)類
2.(編譯時(shí))確定要執(zhí)行的方法簽名
查找所有可訪問(wèn)的適用方法
選擇最具體的匹配方法
3.(運(yùn)行時(shí))確定接收器的動(dòng)態(tài)類別
4.(運(yùn)行時(shí))從動(dòng)態(tài)類中,找到要調(diào)用的方法
在第2步中找到具有相同簽名的方法
否則在超類中搜索等。
10 Java中的一些重要的Object方法
equals() - 如果兩個(gè)對(duì)象“相等”,則為true
hashCode() - 用于哈希映射的哈希代碼
toString() - 可打印的字符串表示形式
toString() - 丑陋而無(wú)信息
你知道你的目標(biāo)是什么,所以你可以做得更好
總是覆蓋,除非你知道不會(huì)被調(diào)用
equals&hashCode - 身份語(yǔ)義
如果你想要價(jià)值語(yǔ)義,你必須重寫
否則不要
設(shè)計(jì)好的類不可變類的優(yōu)點(diǎn)
簡(jiǎn)單
本質(zhì)上是線程安全的
可以自由分享
不需要防御式拷貝
優(yōu)秀的積木
如何編寫一個(gè)不可變的類
不要提供任何變值器
確保沒(méi)有方法可能被覆蓋
使所有的領(lǐng)域最終
使所有字段保密
確保任何可變組件的安全性(避免重復(fù)曝光)
實(shí)現(xiàn)toString(),hashCode(),clone(),equals()等。
何時(shí)讓類不可變
總是,除非有充分的理由不這樣做
總是讓小型“價(jià)值類”永恒不變!
何時(shí)讓類可變
類表示狀態(tài)改變的實(shí)體
真實(shí)世界 - 銀行賬戶,紅綠燈
抽象 - 迭代器,匹配器,集合
進(jìn)程類 - 線程,計(jì)時(shí)器
如果類必須是可變的,則最小化可變性
構(gòu)造函數(shù)應(yīng)該完全初始化實(shí)例
避免重新初始化方法
OOP的歷史仿真和面向?qū)ο缶幊痰钠鹪?/p>
20世紀(jì)60年代:Simula 67是第一個(gè)由Kristin Nygaardand Ole-Johan Dahl在挪威計(jì)算中心開(kāi)發(fā)的面向?qū)ο笳Z(yǔ)言,用于支持離散事件模擬。 (類,對(duì)象,繼承等)
“面向?qū)ο缶幊蹋∣OP)”這個(gè)術(shù)語(yǔ)最早是由施樂(lè)PARC在他們的Smalltalk語(yǔ)言中使用的。
20世紀(jì)80年代:面向?qū)ο笠呀?jīng)變得非常突出,而其中的主要因素是C ++。
NiklausWirth用于Oberon和Modula-2的模塊化編程和數(shù)據(jù)抽象;
埃菲爾和Java
面向?qū)ο蟮臉?biāo)準(zhǔn)
基本概念:對(duì)象,類,屬性,方法和接口
OOP的獨(dú)特功能
封裝和信息隱藏 繼承和重寫 多態(tài)性,子類型和重載 靜態(tài)和動(dòng)態(tài)調(diào)度
Java中一些重要的Object方法
編寫一個(gè)不可變的類
OOP的歷史
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/71327.html
摘要:抽象函數(shù)引發(fā)的關(guān)系是等價(jià)關(guān)系。所以當(dāng)且僅當(dāng)通過(guò)調(diào)用抽象數(shù)據(jù)類型的任何操作不能區(qū)分它們時(shí),兩個(gè)對(duì)象是相等的。必須為每個(gè)抽象數(shù)據(jù)類型適當(dāng)?shù)囟x操作。一般來(lái)說(shuō),在面向?qū)ο缶幊讨惺褂檬且环N陋習(xí)。 大綱 什么是等價(jià)性?為什么要討論等價(jià)性?三種等價(jià)性的方式==與equals()不可變類型的等價(jià)性對(duì)象契約可變類型的等價(jià)性自動(dòng)包裝和等價(jià)性 什么是等價(jià)性?為什么要討論等價(jià)性? ADT上的相等操作 ADT...
摘要:程序失敗時(shí),很難確定錯(cuò)誤的位置。它保護(hù)客戶免受單位工作細(xì)節(jié)的影響。將前提條件放在中,并將后置條件放入和。涉及可變對(duì)象的契約現(xiàn)在取決于每個(gè)引用可變對(duì)象的每個(gè)人的良好行為。設(shè)計(jì)規(guī)約按規(guī)約分類比較規(guī)約它是如何確定性的。 大綱 1.編程語(yǔ)言中的功能/方法2.規(guī)約:便于交流的編程,為什么需要規(guī)約 行為等同規(guī)約結(jié)構(gòu):前提條件和后條件測(cè)試和驗(yàn)證規(guī)約3.設(shè)計(jì)規(guī)約分類規(guī)約圖表規(guī)約質(zhì)量規(guī)約4.總結(jié) 編程...
摘要:所有變量的類型在編譯時(shí)已知在程序運(yùn)行之前,因此編譯器也可以推導(dǎo)出所有表達(dá)式的類型。像變量的類型一樣,這些聲明是重要的文檔,對(duì)代碼讀者很有用,并由編譯器進(jìn)行靜態(tài)檢查。對(duì)象類型的值對(duì)象類型的值是由其類型標(biāo)記的圓。 大綱 1.編程語(yǔ)言中的數(shù)據(jù)類型2.靜態(tài)與動(dòng)態(tài)數(shù)據(jù)類型3.類型檢查4.易變性和不變性5.快照?qǐng)D6.復(fù)雜的數(shù)據(jù)類型:數(shù)組和集合7.有用的不可變類型8.空引用9.總結(jié) 編程語(yǔ)言中的數(shù)據(jù)...
摘要:本次實(shí)驗(yàn)訓(xùn)練抽象數(shù)據(jù)類型的設(shè)計(jì)規(guī)約測(cè)試,并使用面向?qū)ο缶幊碳夹g(shù)實(shí)現(xiàn)。改成泛型將函數(shù)聲明和調(diào)用等修改一下即可調(diào)用之前我們實(shí)現(xiàn)的一個(gè)圖結(jié)構(gòu)實(shí)現(xiàn)方法如下讀取文件輸入,識(shí)別序列,構(gòu)建圖結(jié)構(gòu)。 本次實(shí)驗(yàn)訓(xùn)練抽象數(shù)據(jù)類型(ADT)的設(shè)計(jì)、規(guī)約、測(cè)試,并使用面向?qū)ο缶幊蹋∣OP)技術(shù)實(shí)現(xiàn) ADT。 3.1 Poetic Walks建立對(duì)ADT的基本印象,比如如何設(shè)計(jì)一個(gè)能夠泛型化的ADT。加深對(duì)AF...
摘要:二面向?qū)ο蟾攀雒嫦蜻^(guò)程的設(shè)計(jì)思想和面向?qū)ο蟮脑O(shè)計(jì)思想我要吃魚香肉絲蓋飯面向過(guò)程我買菜我洗菜我切菜我放水我點(diǎn)火我做飯我炒菜。。。。 大家好,上次我們講過(guò)了樂(lè)字節(jié)Java編程之方法、調(diào)用、重載、遞歸,接下來(lái)我們將會(huì)進(jìn)入到Java封裝的內(nèi)容。Java編程語(yǔ)言發(fā)展,面向?qū)ο蠛皖悺?一、編程語(yǔ)言的發(fā)展 機(jī)器語(yǔ)言——直接由計(jì)算機(jī)的指令組成,指令、數(shù)據(jù)、地址都以0和1組成:可以被計(jì)算機(jī)直接識(shí)別并執(zhí)行...
閱讀 1164·2021-11-15 18:00
閱讀 2965·2021-09-22 15:18
閱讀 2026·2021-09-04 16:45
閱讀 817·2019-08-30 15:55
閱讀 4013·2019-08-30 13:10
閱讀 1432·2019-08-30 11:06
閱讀 2055·2019-08-29 12:51
閱讀 2372·2019-08-26 13:55