![](/img/trans.png)
[英]Is it possible to instantiate a Java Annotation given a Class<? extends Annotation>?
[英]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;
//允許
如果元素的類型匹配,則ArrayList
是List
的子類型:
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.Class
是final
一個,它將有助於回答以下兩個問題,其中的組合將回答上述問題。 :)
所以,
List<Class<Override>>
是什么意思? List<Class<Override>>
表示我們只能添加Class<Override>
實例,而不能添加其他任何內容。 這很好,知道我們甚至不能添加Class<Override>
子類,因為Class
類型是final
。
List<Class<? extends Annotation>>
List<Class<? extends Annotation>>
是什么意思? 這種類型的List
代表的類名單,所有這些都是子類的全家 Annotation
類型,這意味着我們能夠成功地添加任何注釋類型(例如, SuppressWarnings.class
, Override.class
, Documented.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.