在看 Alibaba 开发手册时遇到 PECS 原则,刚开始阅读时感觉比较绕,也搜索了一些博文参考,个人觉得 Stackoverflow 的这篇文章比较实用 —— What is PECS (Producer Extends Consumer Super)?
后面结合 JDK 源码梳理了下
// java/util/List.class
public interface List<E> extends Collection<E> {
......
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
}
对于 sort
方法,参数 Comparator<? super E> c
是消费者,c
会获取从该集合 List<E>
中获取元素进行比较。比较器使用的是 Comparator<? super E> c
,因为其 int compare(T o1, T o2)
方法中参数类型 T 是 E 的父类,那么从集合 List<E>
中获取的元素任何 E 类型的方法都可以调用该 int compare(T o1, T o2)
方法进行比较。
例如,
public static class Animal {
public String name; // The name of the animal
}
public static class Cat extends Animal {
public int speed; // The Running Speed of Cats
public Cat(String name, int speed) {
this.speed = speed;
super.name = name;
}
@Override
public String toString() {
return name;
}
}
public static void main(String[] args) {
List<Cat> list = Lists.newArrayList(new Cat("Cookie", 3), new Cat("Trifle", 2));
// Comparator<Animal>
list.sort(Comparator.comparing((Animal o) -> o.name)); // Cookie, Trifle
list.forEach(System.err::println);
// Comparator<Cat>
list.sort(Comparator.comparing((Cat o) -> o.speed)); // Trifle, Cookie
list.forEach(System.err::println);
}
对于 List<Cat>
,sort
时比较器可以为 Comparator<Animal>
,Cat 继承 Animal,可以把 Cat 作为 Animal消费。更甚至比较器可以为 Comparator<Object>
。
可以想象一下,如果 sort
参数形式为(Comparator<? extends E> c)
,从 List<E>
中获取元素只能保证为 E
类型,但比较器 int compare(T o1, T o2)
方法中参数类型 T 是 E 的子类,T 中某些操作 E 是不能满足的。
// java/util/List.class
public interface List<E> extends Collection<E> {
......
boolean addAll(Collection<? extends E> c);
}
addAll
会把参数 Collection<? extends E> c
中的所有元素以其迭代器返回顺序添加到该 List 末尾。
Appends all of the elements in the specified collection to the end of this list, in the order that they are returned by the specified collection’s iterator (optional operation). The behavior of this operation is undefined if the specified collection is modified while the operation is in progress. (Note that this will occur if the specified collection is this list, and it’s nonempty.)
对于 addAll
方法,参数 Collection<? extends E> c
是生产者,负责提供向 List<E>
末尾添加的元素。
根据PECS原则,这里应该使用 Collection<? extends E> c
而非 Collection<? super E> c
,这样可以保证从集合 c
中获取的元素都是 E
的子类,任何对 E
进行的操作它都可以满足。