现在让我们看一个更现实的例子。一个 java.util.TreeSet <E> 代表一个有序的元素是E类型的树。创建一个TreeSet的一个方法是传递一个 Comparator 对象给构造函数。这个 Comparator将会用来按照需要对TreeSet进行排序。
TreeSet(Comparator <E> c)
Comparator 接口是核心:
interface Comparator <T> { int compare(T fst, T snd); }
假定我们要创建一个 TreeSet <String> 并传递一个合适的 Comparator,我们需要传一个能比较String的Comparator。这可以是一个 Comparator <String>,也可以是一个 Comparator <Object>。然而我们不能用Comparator <Object>来调用上面的构造函数TreeSet(Comparator <E> c)。我们可以使用一个有下限的通配符来得到我们需要的灵活性:
TreeSet(Comparator <? super E> c)
这允许任何可用的Comparator被传递进去。
作为使用下限通配符最终的例子,让我们来看看方法 Collections.max(),它返回一个集合中的最大的元素。
现在,为了让max()能工作,传进来的集合中的所有元素必须实现 Comparatable接口。而且,他们必须都能够被彼此比较(all be comparable to each other)。第一个尝试是:
public static <T extends Comparable <T>> T max(Collection <T> coll)
就是说,方法的参数是某一个能和自己进行比较的T的集合。这限制太严格了。
为什么?考虑一个能和任何对象进行比较的类型:
class Foo implements Comparable <Object> {...} ...
Collection <Foo> cf = ...;
Collections.max(cf); // 应该能工作
cf 中的每个元素都可以和每个cf中的其他元素进行比较,因为每个这样的元素都是一个Foo,它可以和任意的对象进行比较,也可以和另一个Foo进行比较。
但是,使用上面的方法签名,我们发现这个调用被拒绝。推断出来的类型必须是Foo,但是Foo没有实现接口 Comparable <Foo>。
T 精确的(exactly)和自己能比较是不需要的。所需要的是 T能够和它的父类中的一个进行比较,这导出:(注:Collections.max()的实际方法签名更复杂,我们在第10部分再讨论。)
public static <T extends Comparable <? super T>> T max(Collection <T> coll)
这个推论对大多数想让 Comparable 对任意类型生效的用法中都有效:你总是应该使用 Comparable <? super T>。
理解了这个泛型?
最新推荐文章于 2024-07-08 09:50:34 发布