与 Arrays.asList() 不兼容的类型

2022-09-01 05:27:28

在下面的示例中,如果我在列表中有多个类型,它编译正常,但是如果我有一个元素,它会选择不再可分配的不同类型的类型。

// compiles fine
List<Class<? extends Reference>> list = Arrays.asList(SoftReference.class, WeakReference.class);
// but take an element away and it no longer compiles.
List<Class<? extends Reference>> list2 = Arrays.asList(WeakReference.class);
// without giving the specific type desired.
List<Class<? extends Reference>> list3 = Arrays.<Class<? extends Reference>>asList(WeakReference.class);

我确信对此有一个合乎逻辑的解释,但它逃脱了我。

    Error:Error:line (30)error: incompatible types
required: List<Class<? extends Reference>>
found:    List<Class<WeakReference>>

为什么有两个元素可以编译,但一个元素不能编译?

顺便说一句:如果你尝试,很难找到一个简单的例子

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

    Error:Error:line (28)error: incompatible types
required: List<Class<? extends List>>
found:    List<Class<? extends INT#1>>
where INT#1 is an intersection type:
INT#1 extends AbstractList,Cloneable,Serializable

这也不会编译(它甚至不会解析)

List<Class<? extends AbstractList & Cloneable & Serializable>> list = Arrays.asList(ArrayList.class, LinkedList.class);

Error:Error:line (30)error: > expected
Error:Error:line (30)error: ';' expected

但这编译很好

static abstract class MyList<T> implements List<T> { }
List<Class<? extends List>> list = 
        Arrays.asList(ArrayList.class, LinkedList.class, MyList.class);
List<Class<? extends List>> list = 
        Arrays.<Class<? extends List>>asList(ArrayList.class, LinkedList.class);

编辑:基于马尔科的例子。在这四个示例中,一个不编译,其余生成相同类型的相同列表。

List<Class<? extends Reference>> list = new ArrayList<>();
list.add(SoftReference.class);
list.add(WeakReference.class);
list.add(PhantomReference.class);

List<Class<? extends Reference>> list = new ArrayList<>(
     Arrays.asList(SoftReference.class));
list.add(WeakReference.class);
list.add(PhantomReference.class);

List<Class<? extends Reference>> list = new ArrayList<>(
     Arrays.asList(SoftReference.class, WeakReference.class));
list.add(PhantomReference.class);

List<Class<? extends Reference>> list = new ArrayList<>(
     Arrays.asList(SoftReference.class, WeakReference.class, PhantomReference.class));

答案 1

有趣的问题。我认为正在发生的事情是这样的。当您有两个元素(如您所示)时,return type from 是所有参数的最具体类型,在第一个示例中为 。这与 与 任务兼容。当您具有单个参数时,返回类型是参数的特定类型,这与赋值不兼容,因为泛型不是协变的。asListList<Reference>List<? extends Reference>


答案 2

考虑

    // ok
    List<Object> list3 = Arrays.asList(new Object(), new String());
    // fail
    List<Object> list4 = Arrays.asList(new String());

第二个示例尝试将 a 赋给 a,但失败。List<String>List<Object>

第二个例子可以工作,如果javac查看周围的上下文,考虑目标类型,并推断出在这里可以工作。Java 8可能会做到这一点(我不确定)T=Object

只有在一种情况下,javac(java 5)将使用上下文信息进行类型推断,请参阅 http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.8

我们可以利用它来制定一个解决方法。

public static <R, T extends R> List<R> toList(T... elements)
{
    return Arrays.asList((R[])elements);
}

现在它们可以编译:

    List<Object> list4 = toList(new String());

    List<Class<? extends Reference>> list = toList(SoftReference.class, WeakReference.class);

    List<Class<? extends Reference>> list2 = toList(WeakReference.class);

这是因为无法从参数类型中推断出来,并且方法结果在赋值上下文中,因此javac尝试通过目标类型进行推断。RR

这适用于赋值或返回语句

List<Class<? extends Reference>> foo()
{
    return toList(WeakReference.class);  // "subject to assignment conversion"
}

否则它将无法工作

void bar(List<Class<? extends Reference>> list){...}

bar( toList(WeakReference.class) ); // fail; R not inferred

推荐