Ada*_*ker 5 java generics wildcard
问题在于一般限制:
public List<Class<? extends Annotation>> getAnnotations() {
return new ArrayList<>(Arrays.asList(Override.class));
}
Run Code Online (Sandbox Code Playgroud)
实际返回类型是ArrayList<Class<Override>>
Method期望的List<Class<? extends Annotation>>
Class<Override>
是Class<? extends Annotation>
Class<? extends Annotation> c = Override.class;
//允许的子类型
ArrayList
List
如果元素的类型匹配:
List<? extends Number> l = new ArrayList<Integer>();
//允许,则是a的子类型
但是,这是不允许的:
List<Class<? extends Annotation>> l = Arrays.asList(Override.class);
List<Class<? extends Annotation>> l = new ArrayList<>(Arrays.asList(Override.class));
Run Code Online (Sandbox Code Playgroud)
甚至是可能还是Class
通配符被破坏了?
我认为这是因为 jdk 1.7 类型推断性质。
您可能已经知道,该Arrays.asList(T ... elems)
方法是通用的,但我们很少显式指定我们希望该方法使用的类型参数,因此我们依赖于编译器的类型推断功能。
因此,当编译器看到一条Arrays.asList(Override.class)
语句时,它会推断该方法的类型参数应该替换为Class<Override>
,即我们将拥有以下形式的方法版本:
public List<Class<Override>> asList(Class<Override> ... elems)
Run Code Online (Sandbox Code Playgroud)
但是,如果您将该方法的类型参数显式设置为
List<Class<? extends Annotation>> l =
Arrays.<Class<? extends Annotation>>asList(Override.class);
Run Code Online (Sandbox Code Playgroud)
那么编译器实际上会知道类型参数必须替换为什么,然后该方法的版本.asList()
将是:
public List<? extends Annotation> asList(Class<? extends Annotation> ... elems)
Run Code Online (Sandbox Code Playgroud)
现在这可以很好地编译,因为Class<? extends Annotation>
与Class<Override>
. 在 Java8 中,类型推断功能得到了进一步改进,因此您不必显式设置方法的类型参数.asList()
。
然而,更有趣的问题是
为什么
List<Class<Override>>
不兼容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
代表了一整套类列表,所有类列表都是该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
Run Code Online (Sandbox Code Playgroud)
两个巨大的问题来自于我们试图Override
向 中添加一些非实例overrides
,这是非常错误的。
我们有足够智能的编译器,它实际上可以检测到此类可能的问题,并且抛出编译时错误是阻止我们这样做的方法。
更多信息: