作为Java 泛型在 Eclipse 中编译但不在 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 和 Eclipse Indigo,编译器合规级别为 1.6)
(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>
with 。)因此 javac 和 imho 在概念上比较任何andFoo<?>
似乎是安全的。但是,如果它的类型参数是用通配符参数化的,那么仍然不可能编写一个返回泛型集合的排序列表表示的泛型方法。我试图通过替换 in 来“欺骗”javac ,但这没有用。Foo<A>
Foo<B>
asSortedList
Foo<?>
S extends Comparable<S>
asSortedFooList
EDIT3:后来Rafaelle指出,设计存在缺陷,因为Comparable<Foo<T>>
不需要实现,并且实现Comparable<Foo<?>>
提供相同的功能,通过细化设计解决了最初的问题。
(最初的原因和好处是,aFoo<T>
可能在某些目的上不关心它的具体类型,但仍然使用具体类型的实例T
,它被实例化,用于其他目的。该实例不必用于确定order 等等Foo
,因为它可能在 API 的其他部分中使用。
具体示例:假设每个 Foo 都使用不同类型的参数实例化T
. 的每个实例Foo<T>
都有一个递增的类型 id,int
用于 - 方法的实现compareTo
。我们现在可以对这些不同类型的列表进行排序Foo
,而不关心具体类型T
(用 表示Foo<?>
),并且仍然有一个具体类型的实例T
可供以后处理。)