首先说一下PECS 原则,有过写泛型代码的朋友对此都不陌生,今天也遇到类似的问题,简单记录一下。
1.如果要从集合中读取类型T数据,并且不能写入,可以使用 ? extends E 通配符 ;接受E类型或者E的子类型
2.如果要向集合里写入类型T数据,并且不需要读取, 可以使用 ? super E 通配符; 接收E类型或者E的父类型
3.如果既要存又要取,那么就不要使用任何通配符
具体测试代码如下:
import java.util.ArrayList;
import java.util.List;
/**
* Created by passself on 2018/8/2.
*/
public class PECS {
static class Food{}
static class Fruit extends Food{}
static class Apple extends Fruit{}
public static void main(String[] args) {
List extends Fruit> fruits = null;//new ArrayList<>();//编译错误
//fruits.add(new Food());
//fruits.add(new Fruit());
//fruits.add(new Apple());//编译器只是知道fruits 是Fruit 的某个子类,并不知道这个子类具体是什么,为了类型安全,只好阻止向其中加入任何类型
fruits = new ArrayList();
fruits = new ArrayList();
//fruits.add(new Fruit());
//fruits = new ArrayList();//编译错误
//fruits = new ArrayList extends Fruit>();
Food food = fruits.get(0);
//使用super 效果 表示类型的下界是 T,参数化类型可以是 T 或 T 的超类:
List super Fruit> tempFruits = null;
tempFruits = new ArrayList();
tempFruits = new ArrayList();
//tempFruits = new ArrayList();//编译错误
tempFruits.add(new Fruit());
tempFruits.add(new Apple());
//tempFruits.add(new Food());//编译错误,出于对类型安全的考虑(编译器会自动向上转型),只能加入fruit或者其子类,因为不知道是哪个超类
//Fruit fruit = tempFruits.get(0); //编译错误 编译器并不知道超类具体是什么类,只能返回Object对象,因为Object是任何java类的超类
Object object = tempFruits.get(0);
}
/**
* 说明:
* 如果要从集合中读取类型T数据,并且不能写入,可以使用 ? extends E 通配符 ;接受E类型或者E的子类型
* 如果要向集合里写入类型T数据,并且不需要读取, 可以使用 ? super E 通配符; 接收E类型或者E的父类型
* 如果既要存又要取,那么就不要使用任何通配符
*/
}
其中注释部分是无法编译成功的,也标注相关解释。
补充:
上面正好提到了通配符?来看一下和我们常用的 T通配符的区别.
? 代表不清楚到底是怎样的类型
T 是限定了相关的类型"T"
比如:
List al=new ArrayList();指定集合元素只能是T类型
List extends E> al=new ArrayList extends E>(); 只是知道是E的子类,并不知道是哪个子类,?通配符一般不单独使用,因为单独使用也没有意义,比如:List> al=new ArrayList>();
使用方式有? extends E 或者? super E