类型推断涉及返回类型,通配符和交集类型

时间:2011-06-21 18:00:26

标签: java generics

我正在尝试声明一个包含一个方法的接口,该方法将返回同时实现Comparator<Object>Action的事物列表,即

<T extends Comparator<Object> & Action> List<T> getThings();

编译很好,但是当我尝试调用此方法时会出现问题。我希望能够做到这一点:

List<Action> things = getThings();
List<Comparator<Object>> things = getThings();

当我尝试这样做时,我收到以下编译错误:

 incompatible types; no instance(s) of type variable(s) T exist so that
 java.util.List<T> conforms to java.util.List<javax.swing.Action>
 found   : <T>java.util.List<T>
 required: java.util.List<javax.swing.Action>

以下情况也不起作用:

List<? extends Action> things = getThings();
List<? extends Comparator<Object>> things = getThings();

实现此效果的另一种方法是创建一个扩展Comparator<Object>Action的空接口,并将其用作返回类型,即

public interface ComparatorAction extends Comparator<Object>, Action { }
List<ComparatorAction> getThings();

但我不想这样做。必须有办法做我想做的事,对吧?有什么想法吗?

谢谢!

P.S。我很难为这篇文章提供一个好的头衔,所以随时可以改变它。

3 个答案:

答案 0 :(得分:4)

List<? extends Action> things = getThings();
List<? extends Comparator<Object>> things = getThings();

编辑这是我的第一反应。然后我想到了它,我不认为推理可行,所以我删除了答案。

再次检查规格,他们应该工作。它在JDK7中编译,但在JDK6中失败。我猜他们已修复了一个错误。

编辑2 没有...我再次阅读规范(JLS3#15.12.2.8),现在我认为推理不应该起作用。 JDK6拒绝推断是正确的。 (我怀疑JDK7引入了一个新的错误;推理规则可能会更新,因此JDK7根据新规则是正确的。我不确定)

根据JLS3,首先是通配符捕获,引入了一个新的类型参数W,它具有上限Action。然后推理有这些初始约束:

List<W> >> List<T>
Comparable >> T
Action  >> T

第一个约束产生等式约束T=W,就是这样,推理就完成了。

现在编译器将检查推断的T是否满足其边界,即是否

W :< Comparable
W :< Action

答案是否定的,第一界不能满足。 (IntelliJ显示了一个很好的错误消息(优于javac):“推断类型”?扩展Action'(即W)类型参数'T'不在其范围内;应该实现Comparable“)< / p>

编辑3 问题是在推理之前是否应该存在通配符捕获。这对我来说不太清楚。如果不应该,那么我们有

List<? extends Action> >> List<T>
Comparable >> T
Action  >> T

产生

T :< Action
T :< Comparable

因此T=Comparable & Action

答案 1 :(得分:4)

您还可以参数化调用getThings()的方法。例如:

public static <U extends Comparator<Object> & Action> void main(String[] args) {
    List<U> l = getThings();
    Action a = l.get(0);
    Comparator<Object> c = l.get(0);
}

答案 2 :(得分:0)

当您返回List<T>时,T指的是ActionComparator<Object>的子类型的某些(未知)类型,并且是最低的)列表中所有元素的常见超类型。如果这种类型不存在,您可能会遇到问题。

如果您不关心T是什么,您可以使用类型变量,如Dave Costa建议的那样,或者您可以使用通配符

List<? extends Action> l = getThings();
List<? extends Comparator<Object>> l2 = getThings();