Java 非集合中泛型的PEC

Java 非集合中泛型的PEC,java,generics,collections,bounded-wildcard,Java,Generics,Collections,Bounded Wildcard,Joshua Bloch提出了PEC,其中规定了何时使用?扩展T和?超级T。如果您从集合框架的角度考虑PEC,那么它非常简单。如果向数据结构添加值,请使用?超级T。如果从数据结构中读取,请使用?扩展T。 例如: public class Collections { public static <T> void copy(List<? super T> dest, List<? extends T> src) { for (int

Joshua Bloch提出了PEC,其中规定了何时使用
?扩展T
?超级T
。如果您从集合框架的角度考虑PEC,那么它非常简单。如果向数据结构添加值,请使用
?超级T
。如果从数据结构中读取,请使用
?扩展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));   
    }   
}
公共类集合{

公共静态无效副本(列表为了回答这个问题,让我们以
比较器
为主要的指导性示例

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

更一般地说,你应该从主类型的角度考虑生产者和消费者对每一个通用参数的类型。如果一些<代码>比较器< /代码>类型消耗了<<代码> t>代码>的对象,则PECS规则规定这样的代码>比较器< /代码>的用户可以使用它来比较类型的对象。是
T
的子类型

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

考虑以下比较标准:

Comparator<Number> c = Comparator.comparingInt(Number::intValue);
以及以下
排序
方法:

static <T> void sort(List<T> list, Comparator<T> c) {
    list.sort(c);
}
幸运的是,由于
Comparator
是它所比较的元素类型的使用者,您可以将
sort
方法的签名更改为:

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

非常感谢您的超清晰解释。我想给出一个关于迭代器的进一步示例。如果我设计了一个调用T next()的方法,那么我应该使用?extends来设计签名,因为迭代器现在生成T。它可以被泛化,就像方法中的泛型类使用T一样(就像比较器的情况一样)如果它返回对T的引用,则应该是super(就像迭代器的情况一样)然后它应该被扩展。@FatihArslan是的,这是正确的。例如,如果您有一个方法接收一个
迭代器
,并且您试图传递一个
迭代器
,它将不会编译。但是如果您更改该方法,使它现在接收一个
迭代器
static <T> void sort(List<T> list, Comparator<T> c) {
    list.sort(c);
}
sort(doubles, c);
static <T> void sort(List<T> list, Comparator<? super T> c) {
    list.sort(c);
}
sort(doubles, c);