天天看點

《JAVA程式設計思想》第四版學習 需要我記住的something –接口

一.接口和抽象類提供了一種将接口與實作分開的更加Structured(結構化?)的方法。

      C++隻是間接支援;而Java有關鍵字interface和abstract,提供直接支援。

二.抽象類和方法

      抽象類位于普通類和接口之間的一個中間層次,是建構具有某些未實作的類的一種重要而又必須的方法,因為不可能總是用純接口。

      抽象方法(abstract method) :僅有聲明,沒有方法體,關鍵字abstract。如abstract void f();(類似于C++的純虛函數)。

      抽象基類abstract base class,抽象類abstract class :為繼承類建立一個通用接口,表示所有繼承類的共同部分,而不同的子類用不同的方式表示該接口,目的是通過這個通用接口操縱一系列類(繼承類)。

      抽象類可以包含抽象方法,也可以沒有抽象方法 。當一個類有一個或多個抽象方法時,它必須為抽象的,否則編譯器報錯。

      抽象類不能建立對象(編譯器會報錯);抽象類的繼承類,如需建立其對象,必須實作所有抽象方法(提供定義);否則,繼承類也是抽象類,編譯器強制用abstract關鍵字。

      抽象類使類的抽象性更明确;抽象類也是一種很有用的重構工具 ,因為它使得我們可以很容易的将公共方法沿着繼承層次結構向上移動。

三.接口(interface):完全抽象的類,隻是确定方法簽名和傳回類型,不提供任何具體實作,用來建立類之間的協定。

      接口可以用來實作變種的多重繼承 (一個類實作多個接口,該類可以upcast為任一個接口)。

      關鍵字implements。 實作接口與繼承類類似。實作的方法也為override?可以加@Override。

      接口方法自動public(隻能用public修飾,或者沒有限定符),實作時也必須定義為public;可以有field,隐式static final。

四.完全解耦(decoupling)

      如果方法操作類而非接口,就隻能用該類及其子類,而不能用其它繼承自該類的類。接口放寬了這種限制,是以可以編寫可複用性更好的代碼。

      政策設計模式:方法根據傳遞對象參數不同而具有不同行為。 方法本身包含算法固定不變的部分,而傳遞的對象參數-政策(包含要執行的代碼)包含變化的部分。如果政策是類,那麼方法與該類的強耦合關系,使其不能複用于具有相同接口元素但不是繼承自該類的其它類。使用接口可以實作解耦 ,該方法可以應用于實作了該接口的任意類。

      複用代碼兩種方式:

      1. 用戶端程式員遵循接口編寫類

      2. 當不能修改想要使用的類時,可以使用擴充卡(Adapter)設計模式。擴充卡的代碼接受所擁有類的接口,産生所需要的接口(方法用到的)(代理)。

五.多重繼承

      接口沒有任何具體實作,也就沒有與之相關的存儲空間,是以可以沒有限制的進行多個接口的組合。C++的多重繼承包袱重,每個基類都有自己的實作。Java的多重繼承,隻能繼承一個類,可以組合任意多個接口(implements後接接口清單)。繼承時,類必須在最前面,否則編譯報錯,即extends T implements I1, I2, I3, ...。

      使用接口兩個理由:

      1. 為了能夠向上轉型為多個基類型,以及擷取由此而帶來的靈活性;

      2. 與抽象類相同,阻止建立該類的對象,確定僅僅是建立一個接口。

      使用接口or使用抽象類?

      如果要建立不帶任何方法定義和成員變量的基類,選擇接口。(多重繼承,自然也要選擇接口);

      但不應該總是選擇接口而不是具體的類。因為這種額外級别的間接性,帶來額外的複雜性。抽象性是應真正的需求而生的,必需時,才應該重構接口。恰當的原則是優先選擇類而不是接口 ,從類開始,如果接口的必需性變得非常明确,再進行重構。

      C++中多重繼承的鑽石問題 :C++中的多重繼承,可能形成一種菱形繼承體系,在末端的類對象的兩個基類中,可能存在對于他們共同基類的方法的不同實作,當用末端類對象調用該方法時,就會無法解析;派生類調用父類的構造函數時也存在沖突(多個父類)?參見另一篇文章《鑽石問題》。Java可以避免這種問題 (習題13),因為接口沒有任何實作。

六.擴充接口

      通過繼承,在新接口添加新的方法聲明來擴充接口;

      通過繼承多個接口,将這些接口組合為一個新的接口。

      繼承接口-extends。注意,隻有接口可以extends多個接口(extends後接接口清單),其它情況,extends隻能用于但一類。

七.實作多個接口時的命名沖突問題:接口中的方法完全一樣時不會出問題;當方法差別僅為傳回值不同時就會沖突。

      在打算組合的不同接口中使用相同的方法名會造成代碼可讀性的混亂,應盡量避免。

八.接口的常見用法-政策設計模式。如Java SE5之後的Scanner類,用到Readable接口。

      對于未實作接口的已有類,可以采用擴充卡模式 ,該适配類可以通過繼承已有類和實作所需接口來建立。正是這種方式,使得可以再任何現有類之上添加新的接口,也就讓任何類都可以對以接口為參數的方法進行适配。這正是接口的強大之處。

九.接口中的fields:自動public static final。 SE5之前用接口的這個特性來建立類似于枚舉的類型,SE5之後不需要。

      接口中的fields不能是空白final,但是可以被非常量表達式初始化,初始化發生在域第一次被通路時。fields并不是接口的一部分,值存儲在該接口的靜态存儲區域内。

對于實作了接口的類,可以把該接口的fields當做自己的static final fields。

十.嵌套接口

      接口可以嵌套在其它類和接口内,由此接口可以為private。注意,private接口既可以實作為private内部類,也可以實作為public内部類;但該public類隻能作為自己來用,不能向上轉型為接口。 即private接口是一種強制該接口中的方法定義不添加任何類型資訊(不允許向上轉型)的方式。private接口不能在定義它的類之外實作。

      接口之間也可嵌套。但接口中的接口自動為public,不能為private。實作某個接口時,并不需要實作嵌套在其内部的任意接口。

十一. 接口與工廠:工廠方法(factory method)設計模式是生成遵循某個接口的對象的典型方式。

      在工廠對象上調用建立方法,生成接口的某個實作的對象;這種方式,可以使代碼與接口實作完全分離,因而可以透明的替換各種實作。采用工廠方法常見的原因就是建立架構。