Effective Java 3rd 條目24 靜態(tài)成員類優(yōu)于非靜態(tài)

嵌套類(nested class)是一個定義在另外一個類內部的類叹话。嵌套類應該僅僅是為了服務外部類而存在凌停。如果內嵌類在其他某些情形下有用,那么他應該是一個頂層類圈盔。有四種嵌套類:靜態(tài)成員類(static member class)豹芯、非靜態(tài)成員類(nonstatic member class)匿名類(anonymous class)本地類(local class)驱敲。只有第一種是被認為是內部類铁蹈。這個條目告訴你聲明時候使用哪種嵌套類以及為什么。

靜態(tài)成員類是嵌套類的最簡單的種類众眨。它最好被認為是一個普通類木缝,它只是恰好聲明在另外一個類的內部便锨,而且可以訪問外部類的所有成員,即使這些成員是聲明為私有的我碟。靜態(tài)成員類是它的外部類的靜態(tài)成員放案,而且就像其他靜態(tài)成員一樣遵從同樣的訪問規(guī)則。如果它是聲明為私有的矫俺,那么他僅僅可以在外部類內部訪問吱殉,諸如此類。

靜態(tài)內部類的一個通常使用是作為一個公開協助類厘托,僅僅是和它的外部類聯合使用友雳。例如,考慮一個枚舉铅匹,它描述由計算器支持的操作 (條目34)押赊。Operation枚舉應該是Calculator類的公開靜態(tài)成員。于是Calculator的客戶端應該引用一些操作包斑,這些操作使用像Calculator.Operation.PLUS和Calculator.Operation.MINUS這樣的名字流礁。

在語句構成上,靜態(tài)和非靜態(tài)成員類的唯一區(qū)別在于罗丰,靜態(tài)成員類在它們的聲明中有修飾符static神帅。盡管語法上的相似性,但是這兩種嵌套類是非常不同的萌抵。非靜態(tài)成員類的每個實例與包含類的外部實例相關聯找御。在非靜態(tài)成員類的實例方法里面,你可以調用外部實例(enclosing instance)的方法绍填,或者使用限定的(qualified)this結構體獲得外部實例的引用 [JLS, 15.8.4]霎桅。如果嵌套類的實例的存在脫離它的外部類的實例,那么嵌套類必須是一個靜態(tài)成員類:沒有外部實例讨永,創(chuàng)建一個非靜態(tài)成員類是不可能的滔驶。

當成員類實例創(chuàng)建時,非靜態(tài)成員類實例和它的外部實例的聯系建立住闯,而且在這之后不能改變。通常澳淑,這個聯系是從外部類的實例方法內部比原,通過調用一個非靜態(tài)成員類構造子自動建立的。手動使用enclosingInstance.new MemberClass(args)建立這個聯系杠巡,也是可能的量窘,雖然非常少見。就像你所預料的氢拥,這個聯系在非靜態(tài)成員類實例中占用了空間蚌铜,而且它的構造過程增添了時間锨侯。

非靜態(tài)成員類的一個通常使用是定義一個Adapter[Gamma95],它允許外部類的實例被看成是某個不相關類的實例冬殃。例如囚痴,Map接口的實現通常使用非靜態(tài)成員類實現他們的集合視圖(collection view),它們是由Map’s keySet审葬、entrySet和values返回深滚。相似地,集合接口涣觉,比如Set和List痴荐,它們的實現通常使用非靜態(tài)成員類來實現它們的迭代器:

// 非靜態(tài)成員類的典型使用 
public class MySet<E> extends AbstractSet<E> { 
    ... // 這個類的大部分省略

    @Override public Iterator<E> iterator() { 
        return new MyIterator(); 
    }

    private class MyIterator implements Iterator<E> { 
        ...
    }
}

如果你定義一個成員類,它不需要訪問外部實例官册,那么永遠把static修飾符放在它的聲明中生兆,讓它成為一個靜態(tài)而不是非靜態(tài)成員類。如果你省略這個修飾符膝宁,那么每個實例將有一個它的外部實例的額外隱含引用鸦难。就像前面提到的,存儲這個引用耗費時間和空間昆汹。更為嚴重的是明刷,它可能導致外部實例留存,原本它是適合垃圾收集(條目7)满粗。最終的內存泄漏可能是災難性的辈末。它通常很難監(jiān)測到,因為這個引用是不可見的映皆。

私有靜態(tài)成員類的一個通常使用是代表對象的組件挤聘,這個對象由它們外部類表示。例如捅彻,考慮Map實例组去,它把鍵和值聯系起來。許多Map實例步淹,對于映射中每個鍵值對从隆,有一個內部Entry實例。雖然每個entry和一個映射相聯系缭裆,但是entry的方法(getKey键闺、getValue和setValue)不需要訪問映射。所以澈驼,使用非靜態(tài)成員類來表示entry是很浪費的:私有靜態(tài)成員類是最好的辛燥。如果你在entry聲明中不慎忽略了static修飾符,這個映射仍然是工作的,但是每個entry將包含一個多余的對映射的引用挎塌,這就浪費了空間和時間徘六。

如果正在討論的類是一個導出類的公開或者受保護成員,在一個靜態(tài)和非靜態(tài)成員類之間正確地選擇是非常重要的榴都。在這種情況下待锈,成員類是一個導出API元素,而且在后續(xù)發(fā)布中不能把它從非靜態(tài)改變?yōu)殪o態(tài)成員類缭贡,而不會違反向后兼容性炉擅。

就像你所預料的,匿名類沒有名字阳惹。它不是它的外部類的一個成員谍失。不是和其他成員一起聲明,它是在使用時同時聲明和實例化的莹汤。代碼中一個表達式合法的任何地方快鱼,匿名類也是允許的。當且僅當它們在非靜態(tài)環(huán)境中發(fā)生纲岭,匿名類有外部類抹竹。但是即使它們在靜態(tài)環(huán)境中發(fā)生,它們也不能夠有任何靜態(tài)成員止潮,除了常數變量(constant variable)窃判,它是初始化為常數表達式的final原始或者字符串域,[JLS, 4.12.4]喇闸。

匿名類的應用有許多限制袄琳。除非在它們被聲明時,你不能夠實例化它們燃乍。你不能進行instanceof測試唆樊,或者做需要你命名這個類的任何其他事情。你不能聲明一個匿名類來實現多個接口刻蟹,或者同時擴展一個類和實現一個接口逗旁。使用匿名類的客戶端不能夠調用任何成員,除了從它的超類繼承而來的那些成員舆瘪。因為匿名類發(fā)生在表達式之中片效,它們應該保持簡短(大約十行或者更少),否則可讀性將會受損英古。

在Java添加lambda(第6章)之前淀衣,匿名類是隨手創(chuàng)建小函數對象(function object)處理對象(process object)的優(yōu)選方式,而且哺呜,但是lambda現在是更優(yōu)的(條目42)舌缤。匿名類的另外一個通常使用是靜態(tài)工廠方法的實現(參考條目20中intArrayAsList)。

本地類是四種內嵌類中最少使用某残。一個本地類實際上可以在一個本地變量可以聲明的任何地方聲明国撵,而且遵從相同的作用域規(guī)則。本地類和其他類型的嵌套類有許多相同的特質玻墅。像成員類介牙,它們有名字,而且可以重復使用澳厢。像匿名類环础,只有當它們在非靜態(tài)情形中定義時,它們有外部實例剩拢,而且它們不能保護靜態(tài)成員线得。而且像匿名類,為了不傷害可讀性徐伐,它們應該保持簡短贯钩。

簡要概括,有四種不同嵌套類办素,而且每種有它的位置角雷。如果一個嵌套類需要在單個方法的外部可見,或者太長了而不適合在一個方法內部性穿,那么使用成員類勺三。如果成員類的每個實例需要它外部實例的引用,那么把它變成非靜態(tài)需曾;否則吗坚,把它變成靜態(tài)。假設類屬于一個方法的內部胯舷,如果你需要僅僅從一個位置創(chuàng)建實例刻蚯,而且有描述這個類的特性的已存類,那么把它變成匿名類桑嘶;否則炊汹,把它變成本地類。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末逃顶,一起剝皮案震驚了整個濱河市讨便,隨后出現的幾起案子,更是在濱河造成了極大的恐慌以政,老刑警劉巖霸褒,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異盈蛮,居然都是意外死亡废菱,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來殊轴,“玉大人衰倦,你說我怎么就攤上這事∨岳恚” “怎么了樊零?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長孽文。 經常有香客問我驻襟,道長,這世上最難降的妖魔是什么芋哭? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任沉衣,我火速辦了婚禮,結果婚禮上减牺,老公的妹妹穿的比我還像新娘厢蒜。我一直安慰自己,他們只是感情好烹植,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布斑鸦。 她就那樣靜靜地躺著,像睡著了一般草雕。 火紅的嫁衣襯著肌膚如雪巷屿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天墩虹,我揣著相機與錄音嘱巾,去河邊找鬼。 笑死诫钓,一個胖子當著我的面吹牛旬昭,可吹牛的內容都是我干的。 我是一名探鬼主播菌湃,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼问拘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了惧所?” 一聲冷哼從身側響起骤坐,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎下愈,沒想到半個月后纽绍,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡势似,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年拌夏,在試婚紗的時候發(fā)現自己被綠了僧著。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡障簿,死狀恐怖霹抛,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情卷谈,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布霞篡,位于F島的核電站世蔗,受9級特大地震影響,放射性物質發(fā)生泄漏朗兵。R本人自食惡果不足惜污淋,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望余掖。 院中可真熱鬧寸爆,春花似錦、人聲如沸盐欺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冗美。三九已至魔种,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粉洼,已是汗流浹背节预。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留属韧,地道東北人安拟。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像宵喂,于是被迫代替她去往敵國和親糠赦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內容

  • 概念 嵌套類(nested class) 指被定義在另一個類的內部的類锅棕。嵌套類存在的目的應該只是為他的外圍類(en...
    NekoJiang閱讀 1,265評論 0 2
  • 1. Java基礎部分 基礎部分的順序:基本語法愉棱,類相關的語法,內部類的語法哲戚,繼承相關的語法奔滑,異常的語法,線程的語...
    子非魚_t_閱讀 31,641評論 18 399
  • 目錄 第二章 創(chuàng)建和銷毀對象 1 考慮用靜態(tài)工廠方法替代構造器 對于代碼來說, 清晰和簡潔是最重要的. 代碼應該被...
    高廣超閱讀 1,452評論 0 12
  • 語文: 1.拼音本:ong寫一行(前3個不帶聲調顺少,后四個帶聲調)朋其!ong的拼讀音節(jié)(song.zhong各寫3個王浴!...
    瑞睿家閱讀 160評論 0 0
  • 條條絲絲理不清,煩煩亂亂催人命∶吩常現在處在一個好尷尬的時候氓辣,想找工作,但是又即將面臨答辯袱蚓,數據理不清钞啸,文章寫不出,備...
    阿哲手作閱讀 206評論 0 0