约书亚·布洛赫提出了PECS,规定了何时使用? extends T和? super T的规则。如果你从Collections框架的角度来考虑PECS,那么它是非常简单的。如果向数据结构添加值,请使用? super T。如果从数据结构中读取,请使用? extends T。例如:
public class Collections {
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i = 0; i < src.size(); i++)
dest.set(i, src.get(i));
}
}如果我检查签名
public static <T> void sort(List<T> list, Comparator<? super T> c) 我看到比较器使用? super,所以它应该是一个消费者。看一下代码,比较器c只用来产生东西,因为它被问到比较的逻辑。
一方面,我理解它为什么是超级的,因为作为一个开发人员,我想使用T类的比较器和超类T的比较器,因为T的对象也是T的超类类型。但当我试图从PECS的角度思考时,我无法理解。
PECS是否仅适用于集合框架?如果没有,谁能向我解释一下比较程序在Collections.sort中使用的是什么?
发布于 2019-02-08 02:56:43
为了回答这个问题,让我们将Comparator作为主要的指导性示例。
如果仔细考虑,您会发现Comparator实际上是接收两个类型为T的参数,并返回它们比较的结果(用int表示)。换句话说,它使用两个T类型的实例并生成一个int值。因此,根据PECS规则,它是T的消费者,因此使用? super T。
更一般地,您应该从主类型的角度考虑生产者和消费者,这与其每个泛型参数的类型有关。如果某个Comparator类型使用类型为T的对象,则PECS规则规定该Comparator<T>的用户可以使用它来比较其类型为T的子类型的对象。
作为一个具体的例子,如果你碰巧已经有了比较两个通用Number实例的逻辑(不管它们的具体类型实际上是什么),你可以用它来比较Double实例,因为doubles毕竟是数字。
考虑下面的比较器:
Comparator<Number> c = Comparator.comparingInt(Number::intValue);在这里,比较器c通过只考虑Number实例的整体部分来比较它们(任意数量)。
如果您有以下Double实例列表:
List<Double> doubles = Arrays.asList(2.2, 2.1, 7.3, 0.2, 8.4, 9.5, 3.8);和下面的sort方法:
static <T> void sort(List<T> list, Comparator<T> c) {
list.sort(c);
}(请注意,Comparator参数中没有通配符? super T )。
然后,如果您想对List<Double> doubles列表进行排序,上面的sort方法的签名将要求您传递一个具体的Comparator<Double>。但是,如果您希望使用先前定义的c比较器对List<Double> doubles进行排序,该怎么办?
由于该比较器的类型为Comparator<Number>,而doubles列表的类型为List<Double>,因此以下代码将产生编译错误:
sort(doubles, c);幸运的是,由于Comparator是它所比较的元素类型的使用者,您可以将sort方法的签名更改为:
static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}现在,这段代码将会编译:
sort(doubles, c);https://stackoverflow.com/questions/54575889
复制相似问题