作为 Java generics compile in Eclipse, but not in javac 的跟进,我发布了另一个片段,它在 Eclipse 中编译和运行良好,但在 javac 中引发编译错误。 (这可以防止从中提取代码片段的项目使用 Maven 构建。)
独立的片段:
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<Foo<?>> setOfFoos = new HashSet<Foo<?>>();
List<Foo<?>> sortedListOfFoos = asSortedList(setOfFoos);
}
public static <T extends Comparable<T>> List<T> asSortedList(Collection<T> c) {
List<T> list = new ArrayList<T>(c);
java.util.Collections.sort(list);
return list;
}
public static class Foo<T> implements Comparable<Foo<T>> {
@Override
public int compareTo(Foo<T> o) {
return 0;
}
}
}
在 javac 中编译返回:
Main.java:11: <T>asSortedList(java.util.Collection<T>) in Main cannot be applied to (java.util.Set<Main.Foo<?>>)
List<Foo<?>> sortedListOfFoos = asSortedList(setOfFoos);
^
关于 Foo<?>
的替换与 Foo<String>
上面的代码片段将在 javac 中编译,这意味着问题与使用的通配符有关。由于 Eclipse 编译器应该更宽容,代码片段是否可能不是有效的 Java?
(我使用 javac 1.6.0_37 和编译器合规级别为 1.6 的 Eclipse Indigo)
(EDIT1:包含另一个在 EDIT2 中删除的示例。)
EDIT2: irreputable 提示, 比较 Foo<A>
和 Foo<B>
可能在概念上是错误的,并受到seh的答案的启发。 , 一个工作 asSortedFooList
可以这样写:
public static <T extends Foo<?>> List<T> asSortedFooList(Collection<T> c) {
List<T> list = new ArrayList<T>(c);
java.util.Collections.sort(list);
return list;
}
(在上面的方法定义中用 Comparable<T>
简单替换 Foo<?>
。)
因此,对于 javac 和恕我直言,在概念上比较任何 Foo<A>
似乎是安全的。和 Foo<B>
.但是还是不能写出泛型方法asSortedList
如果其类型参数使用通配符进行参数化,则返回泛型集合的排序列表表示形式。我试图通过替换 Foo<?>
来“欺骗”javac通过 S extends Comparable<S>
在asSortedFooList
,但这没有用。
EDIT3: 稍后 Rafaelle指出,自从实现Comparable<Foo<T>>
以来,设计存在缺陷没有必要,并实现 Comparable<Foo<?>>
提供相同的功能,通过改进设计解决最初的问题。
(最初的原因和好处是,一个 Foo<T>
可能在某些目的不关心它的具体类型,但仍然使用一个具体类型的实例 T
,它被实例化为, 用于其他目的。该实例不必用于确定其他 Foo
中的顺序,因为它可能用于 API 的其他部分。
具体示例:假设每个 Foo 都被实例化为 T
的不同类型参数. Foo<T>
的每个实例具有类型为 int
的递增 ID用于执行 compareTo
-方法。我们现在可以对这些不同类型的列表进行排序 Foo
并且不关心具体类型 T
(用 Foo<?>
表示)并且 仍然 有一个具体类型的实例 T
可供以后处理。)
最佳答案
对我来说这是另一个 javac
漏洞。当您尝试发送 Collection<Foo<?>>
到具有签名的方法:
public static <T extends Comparable<T>> List<T> asSortedList(Collection<T> c)
编译器注意到形式参数 T
有一个上限,所以检查调用者是否遵守约束。 类型参数 是参数化类型 Foo<T>
的(通配符)实例化, 所以如果 Foo<?>
测试将通过是一个 Comparable<Foo<?>>
.基于通用定义:
class Foo<T> implements Comparable<Foo<T>>
我会说这是真的,所以 Eclipse 再次是正确的 javac
有一个错误。这Angelika Langer's entry永远没有足够的联系。另见 the relevant JLS .
你问它是否是类型安全的。我的回答是它类型安全,这表明您的设计存在缺陷。考虑您对 Comparable<T>
的虚构实现界面,我在其中添加了两个字段:
public static class Foo<T> implements Comparable<Foo<T>> {
private T pState;
private String state;
@Override
public int compareTo(Foo<T> other) {
return 0;
}
}
你总是返回0
,所以问题没有被发现。但是当您尝试让它变得有用时,您有两个选择:
- 比较字符串字段
- 比较
T
成员(member)
String
字段始终是 String
,所以你并没有真正从类型变量中受益 T
.另一方面,T
没有其他可用的类型信息,所以在 compareTo()
你只能处理一个普通对象,类型参数也是无用的。您可以通过实现 Comparable<Foo<?>>
实现完全相同的功能
关于带有通配符的 Java 泛型在 Eclipse 中编译,但在 javac 中不编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13534946/