Java:“?extends I”无法转换为“?extends I”

时间:2014-02-25 19:20:00

标签: java generics

此代码:

interface I {}

public class Test {

    TableView<? extends I> table;

    Test(ObservableList<? extends I> list) {
        table = new TableView<>();
        table.setItems(list);
    }
}

...生成此消息:

error: method setItems in class TableView<S> cannot be applied to given types;
       table.setItems(list);
 required: ObservableList<CAP#1>
 found: ObservableList<CAP#2>
 reason: argument mismatch; ObservableList<CAP#2> cannot be converted to ObservableList<CAP#1>
 where S is a type-variable:
   S extends Object declared in class TableView
 where CAP#1,CAP#2 are fresh type-variables:
   CAP#1 extends I from capture of ? extends I
   CAP#2 extends I from capture of ? extends I

两种相同类型之间的类型不匹配怎么样?我错过了什么?

3 个答案:

答案 0 :(得分:5)

在Java Generics中,?通配符不能相同,因为它们代表未知类型。未知类型不能等于其他未知类型。

如果您希望匹配类型,则必须在Test类上定义泛型类型参数,并在整个班级中引用它。

public class Test<T extends I> {

    TableView<T> table;

    Test(ObservableList<T> list) {
        table = new TableView<>();
        table.setItems(list);
    }
}

答案 1 :(得分:2)

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error

“由于我们不知道c的元素类型代表什么,我们不能向它添加对象.add()方法接受类型E的参数,即集合的元素类型。当实际的类型参数是?,它代表一些未知类型。我们传递给add的任何参数都必须是这个未知类型的子类型。由于我们不知道它是什么类型,我们不能传入任何内容。唯一的例外是null,是各种类型的成员。

另一方面,给定List,我们可以调用get()并使用结果。结果类型是未知类型,但我们始终知道它是一个对象。因此,可以安全地将get()的结果赋给Object类型的变量,或者将其作为期望Object类型的参数传递。“(http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

答案 2 :(得分:1)

请勿在变量声明中使用“?extends I”。它不会增加语义值,是您问题的根源。你看到编译器拒绝假设'?'在一个声明中与'?'相同在另一个。这很自然,因为不能保证它们是自然的。我会免除'?'共:

interface I {}

public class Test {

    TableView<I> table;

    Test(ObservableList<? extends I> list) {
        table = new TableView<>();
        table.setItems(list);
    }
}