Tips
《Effective Java, Third Edition》一書英文版已經出版,這本書的第二版想必不少人都讀過,號稱Java四大名著之一,不過第二版2009年出版,到如今已經將近8年的時間,但隨着Java 6,7,8,甚至9的發佈,Java語言發生了深入的變化。
在這裏第一時間翻譯成中文版。供你們學習分享之用。框架
標記接口(marker interface),不包含方法聲明,只是指定(或「標記」)一個類實現了具備某些屬性的接口。 例如,考慮Serializable
接口(第12章)。 經過實現這個接口,一個類代表它的實例能夠寫入ObjectOutputStream
(或「序列化」)。工具
你可能會據說過標記註解(條目 39)標記一個接口是廢棄過期的。 這個斷言是不正確的。 標記接口與標記註解相比具備兩個優勢。 首先,標記接口定義了一個由標記類實例實現的類型;標記註解則不會。 標記接口類型的存在容許在編譯時捕獲錯誤,若是使用標記註解,則直到運行時才能捕獲錯誤。學習
Java的序列化機制(第6章)使用Serializable
標記接口來指示某個類型是可序列化的。 對傳遞給它的對象進行序列化的ObjectOutputStream.writeObject
方法要求其參數可序列化。 若是此方法的參數是Serializable
類型,則在編譯時會檢測到序列化不適當對象的嘗試(經過類型檢查)。 編譯時錯誤檢測是標記接口的意圖,但不幸的是,ObjectOutputStream.write
API沒有利用Serializable
接口:它的參數被聲明爲Object類型,因此嘗試序列化一個不可序列化的對象直到運行時纔會失敗。翻譯
標記接口對於標記註解的另外一個優勢是能夠更精確地定位目標。 若是使用目標ElementType.TYPE
聲明註解類型,它能夠應用於任何類或接口。 假設有一個標記僅適用於特定接口的實現。 若是將其定義爲標記接口,則能夠擴展它適用的惟一接口,保證全部標記類型也是適用的惟一接口的子類型。code
能夠說,Set接口就是這樣一個受限的標記接口。 它僅適用於Collection子類型,但不會添加超出Collection定義的方法。 它一般不被認爲是標記接口,由於它改進了幾個Collection方法的契約,包括add,equals和hashCode。 但很容易想象一個標記接口,它僅適用於某些特定接口的子類型,而且不會改進任何接口方法的契約。 這樣的標記接口能夠描述整個對象的一些約束條件(invariant),或者說明實例有資格被某個其餘類的方法處理(就像Serializable
接口指示實例有資格被ObjectOutputStream
處理的方式)。對象
標記註解優於標記接口的主要優勢是它們是較大的註解工具的一部分。所以,標記註解容許在基於註解的框架中保持一致性。blog
因此何時應該使用標記註解,何時應該使用標記接口?顯然,若是標記適用於除類或接口之外的任何程序元素,則必須使用註解,由於只能使用類和接口來實現或擴展接口。若是標記僅適用於類和接口,那麼問本身問題:「可能我想編寫一個或多個只接受具備此標記的對象的方法呢?」若是是這樣,則應該優先使用標記接口而不是註解。這將使你能夠將接口用做所討論方法的參數類型,這將帶來編譯時類型檢查的好處。若是你能說服本身,永遠不會想寫一個只接受帶有標記的對象的方法,那麼最好使用標記註解。另外,若是標記是大量使用註解的框架的一部分,則標記註解是明確的選擇。接口
總之,標記接口和標記註釋都有其用處。 若是你想定義一個沒有任何關聯的新方法的類型,一個標記接口是一種可行的方法。 若是要標記除類和接口之外的程序元素,或者將標記符合到已經大量使用註解類型的框架中,那麼標記註解是正確的選擇。 若是發現本身正在編寫目標爲ElementType.TYPE
的標記註解類型,請花點時間肯定它是否應該是註釋類型,是否是標記接口是否更合適。ip
從某種意義來講,本條目與條目22的的意思正好相反,條目22的意思是:「若是你不想定義一個類型,不要使用接口」。本條目的意思是:若是想定義一個類型,必定要使用接口。hash