![](/img/trans.png)
[英]What are the compatibility risks of replacing METHOD/FIELD/etc. targets with TYPE_USE
[英]Is it redundant with `TYPE_USE` to declare other `TYPE` targets?
考慮注釋類型Foo
的聲明:
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
@Target({ ANNOTATION_TYPE, TYPE, TYPE_PARAMETER, TYPE_USE })
public @interface Foo {}
在這里,我認為ANNOTATION_TYPE
被TYPE
變得多余,但我想知道TYPE_USE
使什么變得多余。 API是這樣說的:
常量
TYPE_USE
對應於JLS 4.11中的類型上下文,以及兩個聲明上下文:類型聲明(包括注釋類型聲明)和類型參數聲明。例如,其類型被元注釋為......
TYPE_USE
的注釋可以寫在字段的類型上......並且也可以作為修飾符出現,例如,class 聲明。
JLS說的差不多。
這是否意味着目標TYPE_USE
使Foo
的每個其他目標都變得多余? 或者,如果我將它們從聲明中刪除,會有什么變化?
不,恰恰相反——它們幾乎(但不完全)與 TYPE_USE 互斥。
TYPE_USE 指的是在某處注釋類型的用法的概念。 而 TYPE 是指注釋類型。
在 TYPE 意義上對事物進行注釋的示例:
@MyAnno class ThisDefinesAClass {}
在 TYPE_USE 意義上對事物進行注釋的示例:
public void example(List<@ThisIsTypeUse String> names) {}
請注意 TYPE_USE 注釋是如何與類型的USAGE相關聯的,而不是與類型的定義相關聯的。 我們沒有定義 String。 僅僅使用它。
它變得有點瘋狂的地方是這樣的:
public @ThisIsUhWhatIsThis String example() {}
這是模棱兩可的:您是在注釋example
方法的定義,還是在注釋String
的用法,作為example
方法返回類型的一部分?
如果您的注釋被指定為僅允許 TYPE_USE,那么這將被視為注釋String
部分。 如果注釋指定允許 METHOD,那么這被認為是注釋整個方法。
如果它指定允許BOTH ,那么它就是一個奇怪的規則混雜,每次都需要檢查 JLS,因為它們必然是奇怪和混亂的。 因此,最好不要將 TYPE_USE 與其他任何東西混合使用。
有時定義歸結為同一件事,但通常 TYPE_USE 是更好的考慮方式。 例子:
public @NonNull String getFoo() {return foo;}
這個注釋是不明確的。 然而,兩種解釋都得出相同的結論:
此注釋意味着整個方法“getFoo”已被注釋為“NonNull”方法。 雖然人們可以想出許多關於這可能意味着什么的事情,但如果我告訴你它的意思是:“它永遠不會返回 null”,我相信你會發現這是一個完全合理的事情(而且它是,事實上,早於 TYPE_USE 存在的 @NonNull 注釋意味着什么,並且可能出於向后兼容的原因,許多非空注釋仍然像這樣工作:它們針對方法、參數和字段,而不是 TYPE_USE)。
另一種解釋是說這個注釋意味着使用'String'作為返回類型是這樣注釋的:This is a method。 它的返回類型是@NonNull String
,如String
類型,但標記為@NonNull
。 這當然意味着同樣的事情:這個方法不能返回 null。但這種思維方式更有意義。 例如,舊方法意味着您根本無法傳達“此方法的第一個參數必須是 null 指針,或指向 List 的某個實例的指針,它被限制為僅包含字符串”的概念。 那些指向列表所具有的字符串的指針必須全部為非空。 那就是@Nullable List<@NonNull String>
,您需要 TYPE_USE 來表達這樣的概念。
是的,給定TYPE_USE
目標,如果將TYPE
、 ANNOTATION_TYPE
或TYPE_PARAMETER
添加到目標列表,則不會發生任何變化。 TYPE_USE
目標會使所有其他“TYPE”目標變得多余。
在對引入TYPE_USE
常量的JSR進行公開審查期間,共同負責人 Alex Buckley 寫道:
Foo
類型有一個TYPE_USE
目標,因此@Foo
至少可以出現在TYPE
目標允許的地方,其中包括注釋類型的聲明。
再一次,在同一個線程中:
JSR 308 引入了
ElementType.TYPE_USE
,它不僅與類型的使用有關,而且與類型的聲明有關; 從邏輯上講,它是ElementType.TYPE
的“超類型”。
回想一下, ElementType
將其每個常量定義為一個 class 的“語法位置……在其中寫入注釋是合法的”。 按照 Alex 的話, TYPE_USE
並不特定於使用位置,而是聲明和使用位置的包羅萬象。 從邏輯上講, TYPE
位置是TYPE_USE
位置。 同樣的邏輯適用於其他“TYPE”常量,這意味着Foo
的這兩個聲明是等價的:
@Target({ TYPE_USE, TYPE, ANNOTATION_TYPE, TYPE_PARAMETER })
public @interface Foo {} // is the same as:
@Target({ TYPE_USE })
public @interface Foo {}
將TYPE_USE
視為其他“TYPE”位置的超集可能會有所幫助。 亞歷克斯甚至可能想說“超集”而不是“超類型”。 無論哪種方式,結論都是一樣的:僅TYPE_USE
就涵蓋了所有其他“TYPE”位置。
如果常量可以以某種方式重命名,那肯定會有所幫助。 以“TYPE”(而不是“TYPE_USE”)和“TYPE_DECLARATION”(而不是“TYPE”)等名稱命名的包羅萬象,將使事情變得更加清晰。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.