前言
很多人不理解上下限通配符的特征究竟为什么是它的特征,为什么它可以get不能add,为什么它不能get可以add,我明明这样这样那样那样就可以怎样怎样了,都是因为站在上帝视角看待问题。先看一下两者区别,不妨试试思考一下为什么?然后再看看实例,读完后有没有豁然开朗。
Extend和Super区别
上界<? extend Fruit> —> get()
extend上限通配符,用来限制类型的上限,初始化的时候只能传入本类和子类,可以get();add方法受阻。
下界<? super Apple> —> add()
super下限通配符,用来限制类型的下限,初始化的时候只能传入本类和父类,可以add();get方法受阻。
Extend和Super实例
考点:编译器可以支持向上转型,但不支持向下转型。
假如在某种开发环境下,你在编写一个方法,你通过方法让用户传递一个集合进来,你的遵循迪米特法则,不对用户传递来的集合做内部解析(实际上是用户可能用到的类型太多,你根本无法依次用instanceof判断集合中类型):
你尝试这样接收集合List<? extend Fruit>,于是,你知道用户可能传进来的集合为List<Fruit> list = new List<Fruit>()、List<Banana> list = new List<Banana>()、List<RedApple> list = new List<RedApple>()、List<DIYOrange> list = new List<DIYOrange>()等等,凡是继承水果的类,都有可能是集合中的类型,你不能完整预判到用户可能用到的所有子类型,你也不能复刻用户某个自定义的水果子类,所以你仅有的情报为Fruit。此刻你想完成一个add()的业务逻辑,你想add一个Fruit进去,发现根本不可能做到,因为你不能让用户定义的DIYOrange、RedApple…来指向你添加的Fruit。此刻你想完成一个get()的业务逻辑,你想get一个Fruit出来,发现完全行得通,只用Fruit就可以指向Fruit、Apple、Banana、RedApple、DIYOrange…。
你又尝试这样接收集合List<? super Apple>,于是,你知道用户可能传进来的集合为List<Fruit> list = new List<Fruit>()、List<Food> list = new List<Apple>()、List<Food> list = new List<Food>()、List<Object> list = new List<Object>()等等,凡是水果的超类,都有可能是集合中的类型,你不能完整预判到用户可能用到的所有超类,所以你仅有的情报为Apple。此刻你想完成一个add()的业务逻辑,你想add一个Apple进去,发现轻易就能做到,不论用户定义何种类型他们的类型Fruit、Food、Object都能指向你的Apple。此刻你想完成一个get()的业务逻辑,你想get一个Apple出来,发现受到了阻碍,你没办法让你仅有的Apple去指向Fruit、Food、Object类型对象…。
Extend和Super小Tips
①限定通配符总是包括自己。
②如果你既想存,又想取,那就别用通配符。
③不能同时声明泛型通配符上界和下界。
附加知识
T:作用于模板上,用于将数据类型进行参数化,不能用于实例化对象。
?:在实例化对象的时候,不确定泛型参数的具体类型时,可以使用通配符进行对象定义。