PECS 是指 Producer Extends、Consumer Super,即:
那么为什么呢?首先了解两个概念:
协变(covariant)- 向上类型转换
如果 a <= b,那么 f(a) <= f(b),即如果 a 是 b 的子类,f 是类型转换函数,那么 f(a) 是 f(b) 的子类型。
比如 Manager 是 Employee 的子类,List 是范型容器,List<? extends Emloyee> 是 List<Manager> 的父类型
逆变(contravariant)- 向下类型转换
如果 a <= b,那么 f(a) >= f(b),即如果 a 是 b 的子类,f 是类型转换函数,那么 f(b) 是 f(a) 的子类型。
比如 Manager 是 Employee 的子类,List 是范型容器,List<? super Manager> 是 List<Employee> 的父类型
用一个简单的例子进行说明:
x
// Test.java
import java.util.*;
class Employee {}class Manager extends Employee {}
public class Test{ public static void main(String[] args) { List<? extends Employee> list1 = new ArrayList<Manager>(); List<? super Manager> list2 = new ArrayList<Employee>(); }}在上面的例子中:
list1 是只读的,并且读出来的类型是 Employee 或其父类,当向其中添加元素时将报错:
x
// Test.java
import java.util.*;
class Employee {}class Manager extends Employee {}
public class Test{ public static void main(String[] args) { List<Manager> managers = new ArrayList<Manager>(); for (int i = 0; i < 3; i++) { managers.add(new Manager()); } List<? extends Employee> list1 = managers; list1.add(new Employee()); list1.add(new Manager()); }}只能从其中读取元素:
x
// Test.java
import java.util.*;
class Employee {}class Manager extends Employee {}
public class Test{ public static void main(String[] args) { List<Manager> managers = new ArrayList<Manager>(); for (int i = 0; i < 3; i++) { managers.add(new Manager()); } List<? extends Employee> list1 = managers; Employee employee1 = list1.get(0); System.out.println(employee1); }}list2 是只写的,并且写入的元素类型必须是 Manager 或其子类,当从其中读取元素时将报错:
x
// Test.java
import java.util.*;
class Employee {}class Manager extends Employee {}
public class Test{ public static void main (String[] args) { List<Employee> employees = new ArrayList<Employee>(); for (int i = 0; i < 3; i++) { employees.add(new Employee()); } List<? super Manager> list2 = new ArrayList<Employee>(); Employee emloyee1 = list2.get(0); }}只能向其中写入元素:
x
// Test.java
import java.util.*;
class Employee {}class Manager extends Employee {}class CEO extends Manager {}
public class Test{ public static void main(String[] args) { List<? super Manager> list2 = new ArrayList<Employee>(); // 只能写入 Manager 及其子类 list2.add(new Manager()); list2.add(new CEO()); }}可是为什么呢?
综上:
生产方法的参数使用 super,消费方法的参数使用 extends,比如:
xxxxxxxxxx// Test.java
import java.util.*;
class Employee {}class Manager extends Employee {}
public class Test { public static void main(String[] args) { List<Employee> employees = new ArrayList<Employee>(); Test.produce(employees); Test.consume(employees); }
public static void produce(List<? super Employee> employees) { employees.add(new Employee()); employees.add(new Manager()); }
public static void consume(List<? extends Employee> employees) { for (Employee employee: employees) { System.out.println(employee); } }}