10
2018-12-06 08:50:53 +08:00 1
谈一下我的理解。
Java 类型系统中 数组 和 集合 是会让人迷惑的。比如有两个类型,A 和 B,其中 A 是 B 的子类。那么 []A 也是 []B 的子类,可以这么写
```
[]A a = {...};
[]B b = a;
```
但是使用集合时,比如 List。List 和 List 没有半毛钱关系,这两个类型完全没有联系。
那么如何在集合中表达类型的上下限呢?就需要用到 ? 占位符、extends 和 super。
? 是类型占位符,表示这是一个类型,但是具体什么类型未知。比如 List> 表示一个未知类型的 List,但是这不是 raw List。
? 通常和 extends、super 一起使用。作为方法参数时,比如 List,那么 List extends T> 可以接受任何 List,其中 E 是 T 的子类,类型上限为 T ; List super T> 可以接受任何 List,E 是 T 的超类,类型下线为 T。
一个例子是实现 泛型 Number 相加
```
static long sum(List extends Number> numbers) {
long summation = 0;
for (Number number : numbers) {
summation += number.longValue();
}
return summation;
}
```
那么 List、List 等,传入 sum 中:
```
List myInts = asList(1, 2, 3, 4, 5);
List myLongs = asList(1L, 2L, 3L, 4L, 5L);
List myDoubles = asList(1.0, 2.0, 3.0, 4.0, 5.0);
System.out.println(sum(myInts));
System.out.println(sum(myLongs));
System.out.println(sum(myDoubles));
```
如果单纯定义为:
```
static long sum(List numbers) {
long summation = 0;
for (Number number : numbers) {
summation += number.longValue();
}
return summation;
}
```
是没有什么意义的,这时传入 myInts 和 myLongs 会产生编译错误。
```
public static void copy(List super T> dest, List extends T> src)
```
那么实例化时,比如说 T 是 Number。那么可以将 List 拷贝到 List 甚至 List 中:
```
List myInts = asList(1,2,3,4);
List myDoubles = asList(3.14, 6.28);
List myObjs = newArrayList();
copy(myInts, myObjs);
copy(myDoubles, myObjs);
```
最后谈一下 PECS 原则。如果我们只想从集合中读取元素,那么应该使用协变;如果我们只想向集合中加入元素,那么应该使用逆变,这也被称为 PECS 原则 (Produer Extends, Consumer Super)。
楼主如果感兴趣的话,还可以搜一下 Java 类型系统的协变、逆变看一下