自包含的片段:
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)
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; }
(在上述方法定义中用Foo< T>简单替换可比较的< T>)
所以对于javac和imho来说似乎是安全的,在概念上对比任何Foo< A>和Foo B.但是,如果类型参数用通配符参数化,则仍然无法编写通用方法asSortedList,该方法返回一个通用集合的排序列表表示.我试图通过替换Foo<?>“欺骗”javac通过S扩展可比较< S>在asSortedFooList中,但这没有工作.
EDIT3:Rafaelle后来指出,设计中存在缺陷,因为实现了可比较的< Foo>>不是必需的,并且实现可比较的< Foo>>提供相同的功能,通过精心设计解决初始问题.
(最初的原因和好处是,Foo&T可能在某些目的上不关心其具体类型,但仍然使用具体类型T的实例,为了其他目的,它被实例化,这种情况不必用于确定其他Foos之间的顺序,因为它可能用于API的其他部分.
具体示例:假设每个Foo用T的不同类型参数实例化.Foo的每个实例具有类型int的递增id,用于实现compareTo方法.我们现在可以对这些不同类型的Foo进行排序,并且不关心具体的类型T(用Foo表示),并且还有一个具体类型T的实例可以进行后续处理.)
解决方法
public static <T extends Comparable<T>> List<T> asSortedList(Collection<T> c)
编译器注意到形式参数T有一个上限,所以检查被约束是否受到调用者的尊重. type参数是参数化类型Foo< T>的(通配符)实例化,因此如果Foo<> is-a Comparable< Foo<>>.基于通用定义:
class Foo<T> implements Comparable<Foo<T>>
我会说这是真的,所以Eclipse是正确的,javac有一个错误.这个Angelika Langer’s entry从来没有足够的联系.另见the relevant JLS.
你问是否类型安全?我的答案是它是类型安全的,它表明你的设计有缺陷.考虑您的虚拟实施可比较的< 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成员
String字段始终是一个String,所以你不会从类型变量T中受益.另一方面,T没有其他类型的信息可用,所以在compareTo()中,你只能处理一个普通的对象,并且再次该类型参数是无用的.您可以通过实现Comparable< Foo<?>>>实现相同的精确功能.