我正在尝试声明一个包含一个方法的接口,该方法将返回同时实现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。我很难为这篇文章提供一个好的头衔,所以随时可以改变它。
答案 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
指的是Action
和Comparator<Object>
的子类型的某些(未知)类型,并且是最低的)列表中所有元素的常见超类型。如果这种类型不存在,您可能会遇到问题。
如果您不关心T
是什么,您可以使用类型变量,如Dave Costa建议的那样,或者您可以使用通配符
List<? extends Action> l = getThings();
List<? extends Comparator<Object>> l2 = getThings();