面向對象的標準
基本概念:對象,類,屬性,方法和接口
OOP的獨特功能程序員
封裝和信息隱藏 繼承和重寫 多態性,子類型和重載 靜態與動態分派
Java中一些重要的Object方法
設計好的類
面向對象的歷史
總結算法
面向對象的編程方法/語言應該具備類的概念做爲中心概念。
語言應該可以爲類和它的特徵提供斷言(即規範:前置條件,後置條件和不變量)和異常處理,依靠工具生成這些斷言中的文檔,而且可選地在運行時監視它們 時間。數據庫
靜態類型:一個定義良好的類型系統應該經過強制執行一些類型聲明和兼容性規則來保證它接受的系統的運行時類型安全。編程
泛型(Genericity):用於「準備改變」和「爲/重用設計」:應該能夠編寫具備表示任意類型的正式泛型參數的類。數組
繼承(Inheritance):應該能夠將一個類定義爲從另外一個繼承,以控制潛在的複雜性。安全
多態(Polymorphism):在基於繼承的類型系統的控制下,應該能夠將實體(表示運行時對象的軟件文本中的名稱)附加到各類可能類型的運行時對象。模塊化
動態分派/綁定(Dynamic dispatch / binding):在一個實體上調用一個特性應該老是觸發與所附加的運行時對象的類型相對應的特性,這在調用的不一樣執行過程當中不必定是相同的。函數
對象工具
真實世界的物體有兩個特徵:它們都有狀態和行爲。
識別真實世界對象的狀態和行爲是從OOP角度開始思考的好方法。性能
對於你看到的每一個對象,問本身兩個問題,這些現實世界的觀察都轉化爲OOP的世界:
一個對象是一組狀態和行爲
狀態 - 包含在對象中的數據。
行爲 - 對象支持的操做
類
每一個對象都有一個類
類定義了類型和實現
鬆散地說,類的方法是它的應用程序編程接口(API)
靜態與實例變量/類的方法
類成員變量:與類相關聯的變量,而不是類的實例。 您還能夠將方法與類關聯 - 類方法。
不是類方法或類變量的方法和變量稱爲實例方法和實例成員變量。
總結:
靜態方法不與任何特定的類實例關聯,而實例方法(不帶static關鍵字聲明)必須在特定對象上調用。
Java的接口是一種用於設計和表達ADT的有用語言機制,其實現方式是實現該接口的類。
接口和實現
API的多個實現能夠共存
在Java中,API由接口或類指定
一個接口能夠有多種實現
Java接口和類
接口與類
類確實定義了類型
但更喜歡使用接口
問題:打破抽象邊界
接口的優勢
接口指定了客戶端的契約,僅此而已。
爲何有多個實現
不一樣的表現
不一樣的行爲
性能和行爲每每不盡相同
接口總結
減小錯誤保證安全
容易明白
準備好改變
信息隱藏
將精心設計的模塊與很差的模塊區分開來的惟一最重要的因素是其隱藏內部數據和其餘模塊的其餘實施細節的程度。
設計良好的代碼隱藏了全部的實現細節
被稱爲信息隱藏或封裝,是軟件設計的基本原則。
信息隱藏的好處
將構成系統的類分開
加速系統開發
減輕了維護的負擔
啓用有效的性能調整
增長軟件重用
經過接口隱藏信息
使用接口類型聲明變量
客戶端只能使用接口方法
客戶端代碼沒法訪問的字段
但咱們到目前爲止
成員的可見性修飾符
private - 只能從聲明類訪問
protected - 能夠從聲明類的子類(以及包內)
public - 從任何地方訪問
信息隱藏的最佳實踐
仔細設計你的API
只提供客戶須要的功能,其餘全部成員應該是私人的
您能夠隨時在不破壞客戶的狀況下讓私人成員公開
(1)重寫
可重寫的方法和嚴格的繼承
可重寫方法:容許從新實現的方法。
嚴格的繼承
final
final字段:防止初始化後從新分配給字段
final方法:防止重寫該方法
final類:阻止繼承類
重寫
方法重寫是一種語言功能,它容許子類或子類提供已由其超類或父類之一提供的方法的特定實現。
當子類包含一個覆蓋超類方法的方法時,它也可使用關鍵字super調用超類方法。
重寫的時候,不要改變原方法的本意
(2)抽象類
抽象方法和抽象類
抽象方法:
抽象類:
接口:只有抽象方法的抽象類
具體類⇒抽象類⇒接口
(1)三種多態性
特殊多態(Ad hoc polymorphism):當一個函數表示不一樣且可能不一樣種類的實現時,取決於單獨指定類型和組合的有限範圍。 使用函數重載(function overloading)在許多語言中支持特設多態。
參數化多態(parametric polymorphism):當代碼被寫入時沒有說起任何特定類型,所以能夠透明地使用任何數量的新類型。 在面向對象的編程社區中,這一般被稱爲泛型或泛型編程。
子類型多態(也稱爲子類型多態或包含多態):當名稱表示由一些公共超類相關的許多不一樣類的實例。
(2)特殊多態和重載
當函數適用於幾種不一樣的類型(可能不會顯示公共結構)而且可能以不相關的方式表現每種類型時,能夠得到特殊多態。
(3)重載
重載的方法容許您在類中重複使用相同的方法名稱,但使用不一樣的參數(以及可選的不一樣的返回類型)。
重載方法一般意味着對於那些調用方法的人來講會更好一些,由於代碼承擔了應對不一樣參數類型的負擔,而不是在調用方法以前強制調用方執行轉換。
函數重載能夠在不一樣的實現中建立同名的多個方法。
重載是一種靜態多態
重載規則
函數重載中的規則:重載函數必須因參數或數據類型而有所不一樣
重寫與重載
不要混淆覆蓋派生類中的方法和重載方法名稱
(3)參數多態性和泛型編程
當一個函數在一系列類型上統一工做時得到參數多態性; 這些類型一般具備一些共同的結構。
泛型編程是一種編程風格,其中數據類型和函數是根據待指定的類型編寫的,隨後在須要時做爲參數提供的特定類型實例化。
泛型編程圍繞從具體,高效的算法中抽象出來以得到可與不一樣數據表示形式結合的泛型算法來生成各類各樣有用軟件的想法相關。
Java中的泛型
類型變量是一個不合格的標識符。
若是一個類聲明一個或多個類型變量,則該類是通用的。
泛型類:其定義中包含了類型變量
若是聲明瞭類型變量,則interface是通用的。
若是聲明類型變量,則方法是通用的。
類型變量
使用菱形運算符<>來幫助聲明類型變量。
一些Java泛型細節
能夠有多個類型參數
Wildcards通配符,只在使用泛型的時候出現,不能在定義中出現
通用類型信息被擦除(即僅編譯時)
沒法建立通用數組
(4)子類多態性
子類
一個類型是一組值。
相反,這些值都是ArrayList對象或LinkedList對象,或者是實現List的另外一個類的對象。
子類型只是超類型的一個子集
繼承/子類型的好處:重用代碼,建模靈活性
在Java中:每一個類只能直接繼承一個父類; 一個類能夠實現多個接口。
「B是A的子類型」意思是「每一個B都是A.」
在規格方面:「每一個B都符合A的規格」。
靜態檢查子類型
但編譯器沒法檢查咱們是否以其餘方式削弱了規範:
若是你在Java中聲明瞭一個子類型(例如,實現一個接口),那麼你必須確保子類型的規範至少和超類型同樣強。
子類型的規約不能弱化超類型的規約。
子類型多態
子類型多態:不一樣類型的對象能夠被客戶代碼統一處理子類型多態:不一樣類型的對象能夠統一的處理而無需區分
每一個對象根據其類型行爲(例如,若是添加新類型的賬戶,客戶端代碼不會更改)從而隔離了「變化」
Liskov替換原則(LSP):
instanceof
測試某個對象是否爲給定類的運算符
建議:若是可能,避免使用instanceof(),而且從不在超類中使用instanceof()來檢查針對子類的類型。
類型轉換
有時你想要一種不一樣於你已有的類型
若是你知道你有一個更具體的子類型,頗有用
可是若是類型不兼容,它會獲得一個ClassCastException
建議:
動態分派是選擇在運行時調用多態操做的哪一個實現的過程。
肯定在運行時要調用哪一種方法,即對重寫或多態方法的調用可在運行時解決
做爲示例,File對象和Database對象都有一個StoreRecord方法,可用於將人員記錄寫入存儲。 他們的實現不一樣。
一個程序持有一個對象的引用,該對象多是一個File對象或一個數據庫對象。 它多是由運行時間設置決定的,在這個階段,程序可能不知道或關心哪個。
當程序在對象上調用StoreRecord時,須要肯定哪些行爲被執行。
該程序將StoreRecord消息發送給未知類型的對象,並將其留給運行時支持系統以將消息分派給正確的對象。 該對象實現它實現的任何行爲。
動態分派與靜態分派造成對比,其中在編譯時選擇多態操做的實現。
動態分派的目的是爲了支持在編譯時沒法肯定多態操做的適當實現的狀況,由於它依賴於操做的一個或多個實際參數的運行時類型。
靜態分派:編譯階段便可肯定要執行哪一個具體操做。
重載的方法使用靜態分派,而重寫的方法在運行時使用動態分派。
動態分派不一樣於動態綁定(也稱爲動態綁定)。
提早/靜態綁定
每當發生靜態,私有和最終方法的綁定時,類的類型由編譯器在編譯時肯定,而且綁定在那裏和那裏發生。
推遲/動態綁定
重寫父類和子類都有相同的方法,在這種狀況下,對象的類型決定了要執行哪一種方法。 對象的類型在運行時肯定。
動態方法分派
1.(編譯時)肯定要查找哪一個類
2.(編譯時)肯定要執行的方法簽名
3.(運行時)肯定接收器的動態類別
4.(運行時)從動態類中,找到要調用的方法
10 Java中的一些重要的Object方法
equals() - 若是兩個對象「相等」,則爲true
hashCode() - 用於哈希映射的哈希代碼
toString() - 可打印的字符串表示形式
toString() - 醜陋而無信息
equals&hashCode - 身份語義
不可變類的優勢
簡單
本質上是線程安全的
能夠自由分享
不須要防護式拷貝
優秀的積木
如何編寫一個不可變的類
不要提供任何變值器
確保沒有方法可能被覆蓋
使全部的領域最終
使全部字段保密
確保任何可變組件的安全性(避免重複曝光)
實現toString(),hashCode(),clone(),equals()等。
什麼時候讓類不可變
老是,除非有充分的理由不這樣作
老是讓小型「價值類」永恆不變!
什麼時候讓類可變
類表示狀態改變的實體
若是類必須是可變的,則最小化可變性
仿真和麪向對象編程的起源
20世紀60年代:Simula 67是第一個由Kristin Nygaardand Ole-Johan Dahl在挪威計算中心開發的面嚮對象語言,用於支持離散事件模擬。 (類,對象,繼承等)
「面向對象編程(OOP)」這個術語最先是由施樂PARC在他們的Smalltalk語言中使用的。
20世紀80年代:面向對象已經變得很是突出,而其中的主要因素是C ++。
NiklausWirth用於Oberon和Modula-2的模塊化編程和數據抽象;
埃菲爾和Java
面向對象的標準
基本概念:對象,類,屬性,方法和接口
OOP的獨特功能
封裝和信息隱藏 繼承和重寫 多態性,子類型和重載 靜態和動態調度
Java中一些重要的Object方法編寫一個不可變的類OOP的歷史