簡體   English   中英

是否可以使用簽名List實現方法 <Class<? extends Annotation> &gt;在Java?

[英]Is it possible to implement method with signature List<Class<? extends Annotation>> in Java?

問題在於一般限制:

public List<Class<? extends Annotation>> getAnnotations() {
    return new ArrayList<>(Arrays.asList(Override.class));
}

實際返回類型是ArrayList<Class<Override>>
方法需要List<Class<? extends Annotation>> List<Class<? extends Annotation>>

Class<Override>Class<? extends Annotation>的子類型Class<? extends Annotation> Class<? extends Annotation>
Class<? extends Annotation> c = Override.class; //允許

如果元素的類型匹配,則ArrayListList的子類型:
List<? extends Number> l = new ArrayList<Integer>(); //允許

但是,這是不允許的:

List<Class<? extends Annotation>> l = Arrays.asList(Override.class);
List<Class<? extends Annotation>> l = new ArrayList<>(Arrays.asList(Override.class));

它是否可能或Class通配符被破壞?

我認為這是因為jdk 1.7類型的推理性質。

您可能已經知道, Arrays.asList(T ... elems)方法是通用的,但我們很少明確指定我們希望使用該方法的類型參數,因此我們依賴於類型推斷功能。編譯器。

因此,當編譯器看到 Arrays.asList(Override.class)語句時,它將推斷該方法的type-parameter應該用Class<Override> ,即我們有這種形式的方法版本

public List<Class<Override>> asList(Class<Override> ... elems)

但是,如果您明確將方法的類型參數設置

List<Class<? extends Annotation>> l = 
               Arrays.<Class<? extends Annotation>>asList(Override.class);

那么編譯器實際上會知道什么類型參數必須被替換,然后.asList()方法的版本將是:

public List<? extends Annotation> asList(Class<? extends Annotation> ... elems)

現在這將編譯好,因為Class<? extends Annotation> Class<? extends Annotation>Class<Override>兼容。 在Java8中,類型推斷功能得到了進一步改進,因此您無需為.asList()方法顯式設置type-parameter。

然而, 有趣的問題是

為什么List<Class<Override>>List<Class<? extends Annotation>>不兼容List<Class<? extends Annotation>> List<Class<? extends Annotation>>

java.lang.Classfinal一個,它將有助於回答以下兩個問題,其中的組合將回答上述問題。 :)

所以,

  • List<Class<Override>>是什么意思?

List<Class<Override>>表示我們只能添加Class<Override>實例,而不能添加其他任何內容。 這很好,知道我們甚至不能添加Class<Override>子類,因為Class類型是final

  • List<Class<? extends Annotation>> List<Class<? extends Annotation>>是什么意思?

這種類型的List代表的類名單,所有這些都是子類的全家 Annotation類型,這意味着我們能夠成功地添加任何注釋類型(例如, SuppressWarnings.classOverride.classDocumented.class等。)到列表中。

讓我們假設以下示例實際上是正確的:

List<Class<Override>> overrides = Arrays.asList(Override.class);
List<Class<? extends Annotation>> annotations = new ArrayList<>();
annotations = overrides;
annotations.add(SuppressWarnings.class); //HUGE PROBLEM
annotations.add(Documented.class); //ANOTHER HUGE PROBLEM

這兩個巨大的問題都來自於我們正在嘗試一些非加事實Override實例的overrides ,這是非常錯誤的。

我們有足夠聰明的編譯器,可以實際檢測到這些可能的問題,拋出編譯時錯誤是阻止我們這樣做的方法。

更多信息:

如果元素的類型匹配,則ArrayList是List的子類型:

 List<? extends Number> l = new ArrayList<Integer>(); // allowed 

是的,但在您的示例中,元素類型不匹配:

List<Class<? extends Annotation>> l = new ArrayList<Class<Override>>();

當然, Class<Override>Class<? extends Annotation>的子類型Class<? extends Annotation> Class<? extends Annotation> ,但就像List<String>不是List<Object>的子類型一樣, List<Class<Override>>不是List<Class<? extends Annotation>>的子類型List<Class<? extends Annotation>> List<Class<? extends Annotation>> 它將是List<? extends Class<? extends Annotation>>的子類型List<? extends Class<? extends Annotation>> List<? extends Class<? extends Annotation>> 盡管如此, List<? extends Class<? extends Annotation>>

也就是說,你的代碼沒有編譯的原因是在Java 7中,類型推斷在推斷return語句的表達式的類型時沒有考慮方法的返回類型,所以它默認為可以分配給的最具體的類型

Arrays.asList(Override.class)

沒有意識到return語句只能用更靈活的類型編譯(Java 8類型推斷更聰明,順便說一句)。 一種解決方法是明確指定類型參數:

Arrays.<Class<? extends Annotation>(Override.class);

或者首先通過分配一個局部變量給Java 7的類型推斷提供一個提示:

List<Class<? extends Annotation>> list = Arrays.asList(Override.class);
return list;

或者將方法返回類型更改為

List<? extends Class<? extends Annotation>> getAnnotations()

所以推斷類型並不重要。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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