簡體   English   中英

使用 TYPE_USE 聲明其他 TYPE 目標是否多余?

[英]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_TYPETYPE變得多余,但我想知道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目標,如果將TYPEANNOTATION_TYPETYPE_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM