Java中泛型的PECS For generics in Non Collections

PECS For generics in Non Collections

Joshua Bloch来与自己的规则,它说,当使用?T和扩展?超级T.如果你想自己的条件集合框架,那么它是非常简单的。如果你添加值到数据结构,使用?超级T.如果你读取数据结构,使用?扩展。例如:

1
2
3
4
5
6
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));  
    }  
}

如果我检查签名)

1
public static <T> void sort(List<T> list, Comparator<? super T> c)

i湖比较器的使用?A超,所以应该消费。寻找在C代码,比较器是用来产生的东西,因为它是在比较的逻辑。

在一个手,我知道它为什么是一个超级因为我想作为一个开发人员使用comparators类的超类,所以comparators T和T(T,因为对象是超班的类型。但当我试图想在自己的术语,我不明白。

只做自己的收藏扑克的框架?如果有人可以解释我需要什么,以及如何在collections.sort比较器?


为了回答这个问题,我们以Comparator为主要的指导性例子。

如果仔细考虑,您会发现Comparator实际上接收到两个T类型的参数,并返回它们的比较结果(由int表示)。换句话说,它消耗两个T类型的实例,并产生一个int值。因此,按照PECS规则,它是T的消费者,因此使用? super T

更一般地说,您应该从主类型的角度来考虑生产者和消费者,考虑到每个通用参数的类型。如果某些Comparator类型使用T类型的对象,pecs规则规定,此类Comparator的用户可以使用它来比较类型为T子类型的对象。

作为一个具体的例子,如果您碰巧已经有了逻辑来比较两个通用的Number实例(不管它们的具体类型是什么),那么您可以使用它来比较Double实例,因为double毕竟是数字。

考虑下面的比较器:

1
Comparator<Number> c = Comparator.comparingInt(Number::intValue);

这里,比较程序c通过只考虑Number实例的整数部分来比较Number实例(任何数字)。

如果您有以下Double实例列表:

1
List<Double> doubles = Arrays.asList(2.2, 2.1, 7.3, 0.2, 8.4, 9.5, 3.8);

以及以下方法:

1
2
3
static <T> void sort(List<T> list, Comparator<T> c) {
    list.sort(c);
}

(注意,Comparator参数中没有通配符? super T)。

然后,如果您要对List doubles列表进行排序,则上述sort方法的签名将要求您传递一个具体的Comparator。但是,如果您想使用以前定义的c比较器对List doubles进行排序,该怎么办?

由于该比较器的类型为Comparator,而doubles列表的类型为List,以下代码将产生编译错误:

1
sort(doubles, c);

幸运的是,由于Comparator是它比较的元素类型的使用者,您可以将sort方法的签名更改为:

1
2
3
static <T> void sort(List<T> list, Comparator<? super T> c) {
    list.sort(c);
}

现在,这段代码将编译:

1
sort(doubles, c);