在Java中,List<List<?>>和List<List>是不兼容的类型。

9

我无论如何都不能让这段代码编译通过:

List<List> a = new ArrayList();
List<List<?>> b = new ArrayList();

a = b; // incompatible types
b = a; // incompatible types

似乎在泛型中,java不认为ListList<?>是同一类型。这是为什么呢?是否有解决方法?一个函数的签名为public <T> Set<Class<? extends T>> getSubTypesOf(final Class<T> type)。当传入简单类型时,它可以正常工作,但是对于泛型来说,结果不带通配符参数化,导致javac抱怨原始类型。我想将结果传播到我的应用程序的其余部分,作为Set<Class<? extends GenericTypeHere<?>>>,但是简单的强制转换并不像我期望的那样起作用。编辑:解决方案如下。
@SuppressWarnings({"rawtypes", "unchecked"})
private static Set<Class<? extends GenericTypeHere<?>>> factoryTypes() {
    return (Set) new Reflections("...").getSubTypesOf(GenericTypeHere.class);
}

1
你能给出示例代码展示如何调用它吗? - Philip Couling
2
不幸的是,当原始类型用作泛型类型参数时,规范变得非常模糊。List<List>List<List<?>>之间没有定义转换。我认为我们对此处的上下文了解不足以确定是否适合进行强制转换,但我在我链接到的问答中展示了如何进行转换。 - Radiodef
@Radiodef,他解释得非常完美。 - Oliver Gondža
2个回答

2
好的,所以这是由于微妙的语义差异导致的。
List

这是List的原始类型,它将T等同于Object类型。因此它相当于说:
List<Object>

现在,编译器知道无论发生什么情况,这都是类型为Object的子类。如果您这样做...

List myList = new ArrayList();
myList.add(new Object());

它将正常工作!这是因为Object是相同的,或者是某种类型的派生。

List<?>

这实际上是Java Docs中未知列表的字面意思。我们甚至不知道这里的东西的子类是什么类型的Object。实际上,?类型本身就是一种未知类型。它与Object没有任何关系!这就是为什么当你尝试做..

List<?> myList = new ArrayList<?>();
myList.add(new Object());

你遇到了编译时错误!


3
说“List”并不等同于说“List<Object>”,但你不是第一个在这个页面上提出这种观点的人。这种误解是从哪里来的?我觉得这很奇怪。 - ruakh
ListList<Object>之间共享的语义子集与编译错误无关,这与在泛型子类型规范中缺乏原始类型的包含有关。 - Radiodef
这并没有真正回答问题。 - AlexWien

-2
    List<? extends List> a = new ArrayList();
    List<? extends List<?>> b = new ArrayList();
    a = b;

工作

Set<Class<?extends GenericTypeHere<?>>>

将意味着使用上述通配符答案中提到的Set<Class<YourClass extends AnotherClass<YourClass>>>

是什么阻止您在整个应用程序中使用Set<Class<YourClass extends AnotherClass>>进行传播?


这是一个注释,但它似乎在IDEOne中能够工作,然而如果你使用OP的未编辑代码,你会发现它并不能工作! - christopher
1
不是这样的。ArrayList<List<?>> x = new ArrayList<List>(); 这是一个错误。 - Philip Couling
这并不等同。ArrayList<List> x = new ArrayList<List<?>>();是可行的。 - puj
1
a=b 是可行的,但如果你仔细阅读问题,就会发现 OP 真正想要的是 b=a - Philip Couling

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