泛型转换问题

17

这是我的问题:给定以下类

class A {}
class B extends A {}

这段代码可以编译:

    List<Class<? extends A>> list = Arrays.asList(B.class, A.class);

而这个不行:

    List<Class<? extends A>> anotherList = Arrays.asList(B.class);

怎么回事?


更新:这段代码可以在Java 8中编译。显然是因为“改进的类型推断”。


第一行代码对我来说无法编译。 - tObi
6个回答

14
在第一个例子中,Arrays.asList() 调用的推断类型是 List<Class<? extends A>>,显然可以分配给相同类型的变量。
在第二个例子中,右侧的类型是 List<Class<B>>。虽然 Class<B> 是可分配给 Class<? extends A> 的,但是 List<Class<B>> 不可分配给 List<Class<? extends A>>。它将可分配给 List<? extends Class<? extends A>>
这种情况的原因与 List<B> 不能被分配给 List<A> 的原因相同。如果可以,将可能会导致以下(不安全)代码的出现:
List<Class<B>> bb = new ArrayList<B>();
List<Class<? extends A>> aa = bb;
aa.add(A.class);

明白了。您能指引我去哪里阅读有关推断工作的JLS/Sun教程吗? - Victor Sorokin
Java泛型教程 http://download.oracle.com/javase/tutorial/java/generics/gentypeinference.html - bpgergo
1
@Victor 相关的 JLS 部分似乎是这个:http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#341287 - millimoose
教程大多提到类型推断确实会发生,但没有详细解释。我的直觉理解是,类型推断试图找到最具体的类型参数,以匹配所有方法的编译时类型。 - millimoose

5

这会编译:

List<Class<? extends A>> numbers = Arrays.<Class<? extends A>>asList(B.class);

1
+1 这是正确的解决方案。明确指定参数,因为它与推断的不同。 - newacct

2
Arrays.asList(B.class);

被泛型化为
List<Class<B>> numbers = Arrays.asList(B.class);

因为它只有一个类型为T的属性与参数化类型匹配(在本例中为B.class)。


请问您能否提供指向JLS或Sun教程的指针,以便我可以阅读相关内容? - Victor Sorokin

1
他妈的好问题,我不知道答案,但这里有个解决方法:
List<Class<? extends A>> numbers = new ArrayList<Class<? extends A>>(Arrays.asList(B.class));

1

补充一下,我们可以将代码重写如下

List<Class<? extends A>> asListA = Arrays.asList(B.class, A.class);
List<Class<B>> asListB = Arrays.asList(B.class);

List<Class<? extends A>> numbers = asListA;
List<Class<? extends A>> numbers2 = asListB; // it will fail here

而@Inerdia已经解释了细节。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接