??一個(gè)標(biāo)記接口是一個(gè)接口,沒有包含方法聲明僅委托(或“標(biāo)記”)一個(gè)實(shí)現(xiàn)該接口的類具有某些屬性叉寂。比如狼犯,考慮Serializable接口(第12章).通過實(shí)現(xiàn)這個(gè)接口外里,一個(gè)類指示了它的實(shí)例可以被寫為一個(gè)ObjectOutputStream(或“序列化的”)疏虫。
??你可能會(huì)聽說標(biāo)記注解( item39 )導(dǎo)致標(biāo)記接口過時(shí)了永罚。這個(gè)斷言是不正確的。標(biāo)記接口比標(biāo)記注解有兩個(gè)優(yōu)勢议薪。首先也是最重要的尤蛮, 標(biāo)記接口定義由標(biāo)記類的實(shí)例實(shí)現(xiàn)的類型媳友,標(biāo)記注解不能斯议。標(biāo)記類下的存在允許你在編譯時(shí)間捕獲錯(cuò)誤,如果你使用一個(gè)標(biāo)記注解醇锚,在運(yùn)行時(shí)間之前不能捕獲異常哼御。
??Java的序列化設(shè)施(第六章)使用Serializable標(biāo)記接口來指示一個(gè)類型是可序列化的。ObjectOutputStream.writeObject方法焊唬,用來傳遞序列化的對象恋昼,需要它的參數(shù)是被序列化的。如果該方法的參數(shù)擁有Serializable類型赶促,在編譯時(shí)(通過類型檢查)會(huì)檢測到序列化了不合適的對象液肌。編譯時(shí)間錯(cuò)誤的檢測是標(biāo)記接口的意圖,但是不幸的是鸥滨, ObjectOutputStream.write API并沒有利用Serializable接口的優(yōu)勢:它的參數(shù)被聲明為Object類型嗦哆,所以嘗試序列化一個(gè)未序列化的對象在運(yùn)行時(shí)間并不會(huì)失敗。
??另一個(gè)標(biāo)記接口比標(biāo)記注解的好的地方是它們定位更精確婿滓。如果一個(gè)注解類型通過目標(biāo)ElementType.TYPE聲明老速,它可以應(yīng)用于任何類或接口。假設(shè)你有一個(gè)標(biāo)記只適用于特定接口的實(shí)現(xiàn)凸主。如果你定義它作為標(biāo)記接口橘券,你可以讓他繼承其適用的僅有的接口,確保所有標(biāo)記類型也都是其適用的唯一接口的子類型。
??可以說旁舰,Set接口就只是一個(gè) 受限制的標(biāo)記接口锋华。它只對Collection的子類型適用,但是除了通過Collection定義的方法鬓梅,它沒有添加任何方法供置。它通常不被認(rèn)為是標(biāo)記接口因?yàn)樗纳屏艘恍〤ollection方法的契約,包括add,equals绽快,hashCode.但是很容易想象一個(gè)標(biāo)記接口只適用于一些特定接口的子類型芥丧,并沒有改善任何接口的方法。這樣的標(biāo)記接口可能描述了整個(gè)對象的一些不變量或指示實(shí)例夠資格來處理一些其他類的方法(通過Serializable接口指示實(shí)例符合ObjectOutputStream處理的條件)
??標(biāo)記注解比標(biāo)記接口的主要優(yōu)勢是它們是更大的注解工具的一部分坊罢。因此续担,標(biāo)記注解允許在基于注解的框架中保持一致性。
??那么我們什么時(shí)候應(yīng)該用標(biāo)記注解什么時(shí)候應(yīng)該用標(biāo)記接口呢活孩?如果標(biāo)記應(yīng)用于任何程序元素而不是類或接口時(shí)物遇,明顯你必須使用一個(gè)注解,因?yàn)橹挥蓄惡徒涌谀軌驅(qū)崿F(xiàn)或繼承接口憾儒。如果只允許標(biāo)記類和接口询兴,問你自己一個(gè)問題:我想要編寫一個(gè)或更多只接受這個(gè)標(biāo)記的對象的方法嘛?如果是起趾,你應(yīng)該使用一個(gè)標(biāo)記接口而不是標(biāo)記注解诗舰。這將使您能夠?qū)⒔涌谟米飨嚓P(guān)方法的參數(shù)類型,這將帶來編譯時(shí)類型檢查的好處训裆。如果你可以說服自己你將永遠(yuǎn)不會(huì)想要編寫一個(gè)方法只接受標(biāo)記的對象眶根,你大概更希望使用標(biāo)記注解。此外边琉,如果標(biāo)記是大量使用注解的框架的一部分属百,那么標(biāo)記注解就是明顯的選擇。
??總之变姨,標(biāo)記接口和標(biāo)記注解都有它們的使用場景族扰。如果你想要定義一個(gè)沒有任何新方法關(guān)聯(lián)的類型,標(biāo)記接口才是解決之道定欧。如果你想要標(biāo)記程序元素而不是類和接口或適應(yīng)在框架中的標(biāo)記渔呵,并早已有了注解類型的大量使用,標(biāo)記注解就是正確的選擇忧额。 如果您發(fā)現(xiàn)自己正在編寫目標(biāo)為ElementType.TYPE的標(biāo)記注解類型厘肮,花點(diǎn)時(shí)間弄清楚它究竟應(yīng)該是注解類型,還是標(biāo)記接口更合適睦番。
??某種意義上說类茂,這個(gè)item是Item22( item22 )的倒序耍属,”如果你不想要定義一個(gè)類型,不要使用一個(gè)接口“巩检,最接近的說法是厚骗,”如果你確實(shí)想要定義一個(gè)類型,使用接口“兢哭。
本文寫于2019.7.10领舰,歷時(shí)2天