EffectiveJava讀書筆記三

第4章 類和接口

使類和成員的可訪問性最小化

模塊之間只通過它們的API進行通信, 一個模塊不需要知道其他模塊的工作情況范嘱,這稱之為信息隱藏(information hiding)或封裝(encapsualtion)实苞,是軟件設計的基本原則之一。

靈活使用成員(域、方法奈应、嵌套類和嵌套接口)的四種訪問級別。

  • 私有的(private)
  • 包訪問的(package-private)
  • 受保護的(protected)
  • 公有的(public)
    其中私有和包訪問則是類的實現(xiàn)中的一部分即不會影響它的導出的API购披。
    受保護的成員的應該盡量少用杖挣。
    包含公有可變域的類并不是線程安全的。這一點主要說明的是我們應該多使用不可變的域刚陡,即多使用final來達到我們的目的惩妇。PS:final并不是萬能的解決方案,即當final指向一個可變對象的引用筐乳,同樣也會帶來問題歌殃。

長度非零的數(shù)組總是可變的,所以蝙云,類具有共有的靜態(tài)final數(shù)組域氓皱,或者返回這種域的訪問方法,這幾乎總是錯誤的。如下:

public static final Thing[] values = {...};

有如下的兩種修正方法:

  1. 使公有數(shù)組變成私有的波材,并增加一個公有的不可變列表:
private static final Thing[] PRIVATE_VALUES = {...};
public static final List<Thing> VALUES = Collections.unmodifiableLIst(Arrays.asList(PRIVATE_VALUES));
  1. 使數(shù)組變成私有的股淡,并添加一個公有方法,返回私有數(shù)組的一個備份:
private static final Thing[] PRIVATE_VALUES = {...};
public static final Thing[] values(){
    return PRIVATE_VALUES.clone();
}

總結:應該始終盡可能地降低可訪問性廷区。在仔細地設計了一個最小的公有API之后唯灵,應該防止把任何散亂的類、接口和成員變成API的一部分隙轻。除了公有靜態(tài)final域的特殊情形之外埠帕,公有類都不應該包含公有域。并且要確保公有靜態(tài)final域所引用的對象都是不可變的玖绿。

在公有類中使用訪問方法而非公有域

如果類可以在它所在的包的外部進行訪問敛瓷,就提供訪問方法,以保留將來改變該類的內(nèi)部表示法的靈活性镰矿。

當域不可變的時候琐驴,在讀取域時,可強加約束條件秤标。

公有類永遠都不應該暴露可變的域绝淡。雖然還是有問題,但是讓公有類暴露不可變的域其危害比較小苍姜。但是牢酵,有時候會需要用包級私有的或者私有的嵌套類來暴露域,無論這個類是不變的還是不可變的衙猪。

是可變性最小化

Java平臺類庫中包含的不可變類馍乙,有String,基本類型的包裝類垫释,BigInteger和BigDecimal丝格。不可變的類比可變類更加易于設計、實現(xiàn)和使用棵譬,不容易出錯且更加安全显蝌。

為了使類成為不可變,要遵循下面五條原則:

  1. 不要提高任何會修改對象狀態(tài)的方法订咸。
  2. 保證類不會擴展
  3. 使所有的于都是final的曼尊。
  4. 使所有的域成為私有的。
  5. 確保對于任何可變組件的互斥訪問脏嚷。

采用函數(shù)的做法骆撇,即在方法中返回的是一個新的實例,而不是修改這個實例父叙。

不僅可以共享不可變對象神郊,甚至也可以共享它們的內(nèi)部信息肴裙。如BigInteger類。
不可變對象為其他對象提供了大量的構建涌乳。
不可變類真正唯一的缺點是践宴,對于每個不同的值都需要一個單獨的對象。

為了確保不可變性爷怀,類絕對不允許自身被子類話,除了“使類成為final的”這種方法之外带欢,還有另外一種更加靈活的辦法可以做到這一點:讓類的所有構造器都變成私有的或者包級私有的运授,并添加公有的靜態(tài)工廠(static factory)來代替公有的構造器。

復合優(yōu)先于繼承

繼承打破了封裝性乔煞。換句話說吁朦,子類依賴于其超類中特定功能的實現(xiàn)細節(jié)。超類的實現(xiàn)有可能會隨著發(fā)行版本的不同有所變化渡贾,如果真的發(fā)生了變化逗宜,子類可能遭到破壞,即使它的代碼完全沒有改變空骚。

繼承機制會把超類API中的所有缺陷傳播到子類中纺讲,而復合則允許設計新的API來隱藏這些缺陷。

要么為繼承而設計囤屹,并提供文檔說明熬甚,要么就禁止繼承

為了設計一個類的文檔,以便它能夠被安全地子類化 肋坚,你必須描述清楚那些有可能未定義的實現(xiàn)細節(jié)乡括。

為了允許繼承,類還必須遵守其他一些約束智厌。構造器不能調(diào)用可被覆蓋的方法诲泌。

你可以機械地消除類中可覆蓋方法的自用特性,而不改變它的行為铣鹏。將每個可覆蓋方法的代碼體移到一個私有的"輔助方法(helper method)"中敷扫,并且讓每個可覆蓋的方法調(diào)用它的私有輔助方法。然后吝沫,用“直接調(diào)用可覆蓋方法的私有輔助方法”來代替“可覆蓋方法的每個自用調(diào)用”呻澜。

接口優(yōu)于抽象類

Java只允許單集成,所以抽象類作為類型定義受到了極大的限制惨险。而相對地羹幸,接口則有以下好處:

  • 現(xiàn)有的類可以很容易被更新,以實現(xiàn)新的接口辫愉。(抽象類則需要修改類層次栅受,單繼承也會給我們帶來不小的困擾。)
  • 接口是定義mixin(混合類型)的理想選擇。
  • 接口允許我們構造非層次結構的類型框架屏镊。

Sometime, 我們需要對接口來提供一個抽象的骨架實現(xiàn)類(skeletal implementation), 把接口和抽象類的優(yōu)點結合起來依疼。骨架實現(xiàn)通常會以 AbstractInterface的形式出現(xiàn),如 Collections Framework中的AbstractCollection而芥、AbstractSet律罢、AbstractList和AbstractMap。

抽象類的演變比接口的演變要容易得多棍丐。在抽象類中增加新的方法误辑,則該抽象類的所有現(xiàn)有實現(xiàn)都將提供這個新的方法。對于接口歌逢,這樣做是行不通的巾钉。

總結: 接口通常是定義允許多個實現(xiàn)的類型的最佳途徑。一個例外就是秘案,當演變的容易性比靈活性和功能更為重要的時候砰苍,這種情況下,應該使用抽象類阱高,但前提是必須理解并且可以接受這些局限性赚导。如果導出了一個重要的接口,就應該堅決考慮同時提供骨架實現(xiàn)類讨惩。最后辟癌,應該盡可能謹慎地設計所有的公有接口,并通過編寫多個實現(xiàn)來對它們進行全面的測試荐捻。

接口只用于定義類型

接口應該只被用來定義類型黍少,不應該被用來導出常量。常量接口模式是對接口的不良使用处面。應該使用不可實例化的工具類(utility class)來導出這些常量厂置。

如果大量利用工具類導出的常量,可以通過利用靜態(tài)導入(static import)機制魂角,避免用類名來修飾常量名昵济,(靜態(tài)導入機制是在Java1.5中才引入的)。

類層次優(yōu)于標簽類

標簽類是指帶有兩種設置更多風格的實例的類野揪,并包含實例風格的標簽(tag)域访忿。
它有著有多缺點,其中充斥著樣板代碼斯稳,包括枚舉聲明海铆、標簽域及條件語句。一句話:標簽類過于冗長挣惰,容易出錯卧斟,并且效率低下殴边。

解決方法:使用子類型化(subtyping)為每種原始標簽類定義根類的具體子類。

類層次的另一種好處:可以反映類型之間本質(zhì)上的層次關系珍语,有助于增強靈活性锤岸,并進行更好的編譯時類型檢查。

用函數(shù)對象表示策略

常用的比較器函數(shù)就代表一種為元素排序的策略板乙。

總結:函數(shù)指針的主要用途就是實現(xiàn)策略(Strategy)模式是偷。為了在Java實現(xiàn)這種模式,要聲明一個接口來表示該策略募逞,并且為每個具體策略聲明一個實現(xiàn)了該接口的類晓猛。當一個具體策略只被使用一次時,通常使用匿名類來聲明和實例化這個具體策略類凡辱。當一個具體策略是設計用來重復使用過的時候,它的類通常就要被實現(xiàn)為私有的靜態(tài)成員類栗恩,并通過公有的靜態(tài)final域被導出透乾,其類型為該策略接口。

優(yōu)先考慮靜態(tài)成員類

嵌套類(nested class)是指被定義在另一個類的內(nèi)部的類磕秤。其有四種:靜態(tài)成員類(static member class)乳乌、非靜態(tài)成員類(nonstatic member class)、匿名類(anonymous class)市咆、和局部類(local class)汉操,后三種都被成為內(nèi)部類(inner class)。

靜態(tài)成員類可以訪問外圍類的所有成員蒙兰,包括哪些聲明為私有的成員磷瘤。靜態(tài)成員類是外圍類的一個靜態(tài)成員,與其他的靜態(tài)成員一樣搜变,也遵守同樣的可訪問性規(guī)則采缚。如果被聲明為私有的,它則只能在外圍類的內(nèi)部才可以被訪問挠他。
常見的地方:Map的集合視圖(collection view)keySet扳抽、entrySet和Values;Set和List集合接口中的迭代器(iterator)殖侵。

非靜態(tài)成員類的每個實例都隱含著與外部類的一個外圍實例(enclosing instance)相關聯(lián)贸呢。這種關聯(lián)關系需要消耗非靜態(tài)成員類實例的空間,并且增加了構造的時間開銷拢军。

當且僅當匿名類出現(xiàn)在非靜態(tài)的環(huán)境中楞陷,它才有外圍實例。當出現(xiàn)在靜態(tài)的環(huán)境中朴沿,則不會用于任何靜態(tài)成員猜谚。常用用法是動態(tài)地創(chuàng)建行數(shù)對象(function object);創(chuàng)建過程對象(process object)如败砂,Runnable, Thread 或 TimerTask實例;在靜態(tài)工廠方法的內(nèi)部魏铅。

局部類有名字昌犹,可以被重復地使用。與匿名類一樣览芳,只有在非靜態(tài)環(huán)境中定義的時候斜姥,才有外圍實例,它們也不能包含靜態(tài)成員沧竟。

** 總結:** 四種嵌套類各有用途铸敏。若果一個嵌套類需要在單個方法之外仍然是可見的,或者太長了悟泵,不適合在方法內(nèi)部杈笔,就應該使用成員類。如果成員類的每個實例都需要一個指向其外圍實例的引用糕非,就要把成員類做成非靜態(tài)的蒙具;否則,就做成靜態(tài)的朽肥。假設這個嵌套類屬于一個方法的內(nèi)部禁筏,如果你只需要在一個地方創(chuàng)建實例,并且已經(jīng)有了一個預置的類型可以說明這個類的特征衡招,就要把它做成匿名類篱昔;否則就做成局部類。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末始腾,一起剝皮案震驚了整個濱河市州刽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌浪箭,老刑警劉巖怀伦,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異山林,居然都是意外死亡房待,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門驼抹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來桑孩,“玉大人,你說我怎么就攤上這事框冀×鹘罚” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵明也,是天一觀的道長宣虾。 經(jīng)常有香客問我惯裕,道長,這世上最難降的妖魔是什么绣硝? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任蜻势,我火速辦了婚禮,結果婚禮上鹉胖,老公的妹妹穿的比我還像新娘握玛。我一直安慰自己,他們只是感情好甫菠,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布挠铲。 她就那樣靜靜地躺著,像睡著了一般寂诱。 火紅的嫁衣襯著肌膚如雪拂苹。 梳的紋絲不亂的頭發(fā)上图甜,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天扫沼,我揣著相機與錄音,去河邊找鬼缅阳。 笑死带迟,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的囱桨。 我是一名探鬼主播仓犬,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼舍肠!你這毒婦竟也來了搀继?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤翠语,失蹤者是張志新(化名)和其女友劉穎叽躯,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肌括,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡点骑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了谍夭。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片黑滴。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖紧索,靈堂內(nèi)的尸體忽然破棺而出袁辈,到底是詐尸還是另有隱情,我是刑警寧澤珠漂,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布晚缩,位于F島的核電站尾膊,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏荞彼。R本人自食惡果不足惜冈敛,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望卿泽。 院中可真熱鬧莺债,春花似錦、人聲如沸签夭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽第租。三九已至措拇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間慎宾,已是汗流浹背丐吓。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留趟据,地道東北人券犁。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像汹碱,于是被迫代替她去往敵國和親粘衬。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容

  • 類與接口是Java語言的核心,設計出更加有用跪腹、健壯和靈活的類與接口很重要褂删。 13、使類和成員的可訪問性最小化 設計...
    Alent閱讀 675評論 0 2
  • 1.使類和成員的可訪問性最小化 訪問修飾符: private protected public 頂層的(非嵌套)類...
    666真666閱讀 836評論 0 1
  • 一:java概述:1冲茸,JDK:Java Development Kit屯阀,java的開發(fā)和運行環(huán)境,java的開發(fā)工...
    ZaneInTheSun閱讀 2,635評論 0 11
  • 回答 卑鄙是卑鄙者的通行證轴术, 高尚是高尚者的墓志銘蹲盘, 看吧,在那鍍金的天空中膳音, 飄滿了死者彎曲的倒影召衔。 冰川紀過去...
    水鄉(xiāng)醉客閱讀 605評論 1 5
  • 簡介:遭到初戀的背叛,在職場的洗禮祭陷,與藍顏扯不清理還亂的糾葛苍凛,看豪放女路小莫的成長經(jīng)歷趣席。難以自拔的初戀,讓路小莫學...
    hi羽佳閱讀 343評論 0 1