前段时间看《Java编程思想》泛型时对 <? extends T>与<? super T>很懵逼,接着看到泛型与集合的更蒙蔽,随后又翻开《码出高效》时,对这些知识点才恍然大悟,发篇博客记录下

List、List<Object>、List<?> 的三者的区别以及 <? extends T>与<? super T> 的区别

List、List<Object>、List<?>

  • List :完全没有类型限制和赋值限定。
  • List<Object> :看似用法与List一样,但是在接受其他泛型赋值时会出现编译错误。
  • List<?>:是一个泛型,在没有赋值前,表示可以接受任何类型的集合赋值,但赋值之后不能往里面随便添加元素,但可以remove和clear,并非immutable(不可变)集合。List<?>一般作为参数来接收外部集合,或者返回一个具体元素类型的集合,也称为通配符集合

代码验证:(感觉用博客的页面插入代码效果不好,在此处贴了图片,代码在文章末尾补上)



<? extends T>与<? super T>

List 最大的问题是只能放置一种类型,如果随意转变类型的话,就是破窗理论,泛型就失去了意义。为了放置多种受泛型约束的类型,出现了 <? extends T>与<? super T> 两种语法。简单来说, <? extends T> 是Get First,适用于,消费集合元素的场景;<? super T>是Put First,适用于,生产集合元素为主的场景。

  • <? extends T> :可以赋值给任意T及T的子类集合,上界为T,取出来的类型带有泛型限制,向上强制转型为T。null 可以表示任何类型,所以null除外,任何元素都不得添加进<? extends T>集合内。
  • <? super T> : 可以复制T及任何T的父类集合,下界为T。再生活中,投票选举类似于<? super T>的操作。选举投票时,你只能往里投票,取数据时,根本不知道时是谁的票,相当于泛型丢失

<? extends T>的场景是put功能受限,而<? super T>的场景是get功能受限

代码示例如下(以加菲猫、猫、动物为例,说明extends和super的详细语法差异0):





在代码第二段中的23行编译时报错:

Type mismatch: cannot convert from List to List<? extends Cat>

因为List赋值给List时会编译出错,因为能赋值给<? extends Cat>的类型,只有Cat和它的子类。因为<? extends Cat>泛型信息表示的是,此笼子(容器)内的全部都是猫,而List笼子(容器)内可能住着毒蛇,鳄鱼、豹猫(猫的天敌)、大型猛禽等动物,不能把它们放同一个笼子(容器)里。 26,27行中,把List赋值给 <? extends T>与<? super T> 都是可以的。

在第三段代码的36、36、37行均编译出错:

The method add(capture#1-of ? extends Cat) in the type List<capture#1-of ? extends Cat> is not applicable for the arguments (Animal)

无法进行add操作,这是因为除null外,任何元素都不能添加进<? extends T>集合中。但<?super Cat>可以往里面添加元素,但只能添加Cat自身即其子类对象,如上面代码中的41、42行。因为猫的笼子中只能关猫,不能关其他动物,如代码中的40行。

在上面代码中的第四段中,所有的 List<? super T>集合 都能执行get方法返回元素,但是泛型丢失,只能返回object对象,如上面代码中的46、47、48行。List<? extends T>集合 可以返回带类型的元素,但只能返回Cat自身及其父类对象,因为子类对象被擦除了,如代码中的50到54行。

附:

第一张图片中的代码

import java.util.ArrayList;
import java.util.List;
public class TestArrayList {
public static void main(String[] args) { //第一段:泛型出现之前集合定义方式
List a1 =new ArrayList();
a1.add(new Object());
a1.add(new Integer(10));
a1.add(new String("string")); //第二段:把a1引用赋值给a2,(a2与a1的区别是增加了泛型限制)
List<Object> a2 =a1;
a2.add(new Object());
a2.add(new Integer(20));
a2.add(new String("string2"));
a2.add(25);
//List<Object> 接受其他泛型赋值时,会报异常(因为在下面例子中List<Integer>不能转为List<Object>)
List<Integer> aint = new ArrayList<Integer>();
List<Object> a22 =aint;//Type mismatch: cannot convert from List<Integer> to List<Object> //第三段:把a1引用赋值给a3,(a3与a1的区别是增加了泛型<Integer>)
List<Integer> a3 = a1; //此时如果遍历a3则会报类型转换异常ClassCastException
a3.add(new Integer(20));
//下面两行编译出错,不允许增加非Integer类型进入集合
a3.add(new Object());//The method add(Integer) in the type List<Integer> is not applicable for the arguments (Object)
a3.add(new String("string2")); //第四段:把a1引用赋值给a4,a4与a1的区别是增加了通配符
List<?> a4 = a1;
//允许删除和清除元素
a4.remove(0);
a4.clear();
//编译错误,不允许添加任何元素
a4.add(new Object());//The method add(capture#3-of ?) in the type List<capture#3-of ?> is not applicable for the arguments (Object)
a4.add(new Integer(20));
a4.add(new String("string2"));
}
}

第二张图片中的代码

import java.util.ArrayList;
import java.util.List;
class Animal{}
class Cat extends Animal{}
class Garfield extends Cat{} //用动物,猫,加菲猫的继承关系说明extends与super在集合中的意义
public class AnimalCatGarfield {
public static void main(String[] args) {
//第一段:声明第三个依次继承的集合:Object>动物>猫>加菲猫 三个泛型集合可以理解为三个不同的笼子
List<Animal> animal = new ArrayList<Animal>(); //动物
List<Cat> cat = new ArrayList<Cat>(); //猫
List<Garfield> garfield = new ArrayList<Garfield>(); //加菲猫 animal.add(new Animal());
cat.add(new Cat());
garfield.add(new Garfield()); //第二段:测试赋值操作 以Cat为核心,因为它既有子类又有父类
//下行编译出错。只能赋值Cat或Cat子类集合
List<? extends Cat> extendsCatFromAnimal = animal;
List<? super Cat> superCatFromAnimal = animal; List<? extends Cat> extendsCatFromCat = cat;
List<? super Cat> superCatFromCat = cat; List<? extends Cat> extendsCatFromGarfield = garfield;
//下行编译出错。只能赋值Cat或着Cat父类集合
List<? super Cat> superCatFromGarfield = garfield; //第三段:测试add方法
//下面三行中所有的<? extends T>都无法进行add操作,编译出错
extendsCatFromCat.add(new Animal());
extendsCatFromCat.add(new Cat());
extendsCatFromCat.add(new Garfield()); //下行编译出错。只能添加Cat或者Cat的子类集合。
superCatFromCat.add(new Animal());
superCatFromCat.add(new Cat());
superCatFromCat.add(new Garfield()); //第四段:测试get方法
//所有的super操作能够返回元素,但是泛型丢失,只能返回object对象
Object object1 = superCatFromCat.get(0);
Animal object = superCatFromCat.get(0);//Type mismatch: cannot convert from capture#8-of ? super Cat to Animal
Cat object3 = superCatFromCat.get(0);//
//以下extends操作能够返回元素
Animal catExtends3 = extendsCatFromCat.get(0);
Object catExtends2 = extendsCatFromCat.get(0);
Cat catExtends1 = extendsCatFromCat.get(0);
//下行编译错误。虽然Cat集合从Garfield赋值而来,但类型擦除后,是不知道的
Garfield cat2 = extendsCatFromGarfield.get(0);
}
}

一文搞懂List 、List<Object>、List<?>的区别以及<? extends T>与<? super T>的区别的更多相关文章

  1. 夯实Java基础系列6:一文搞懂抽象类和接口,从基础到面试题,揭秘其本质区别!

    目录 抽象类介绍 为什么要用抽象类 一个抽象类小故事 一个抽象类小游戏 接口介绍 接口与类相似点: 接口与类的区别: 接口特性 抽象类和接口的区别 接口的使用: 接口最佳实践:设计模式中的工厂模式 接 ...

  2. 一文搞懂所有Java集合面试题

    Java集合 刚刚经历过秋招,看了大量的面经,顺便将常见的Java集合常考知识点总结了一下,并根据被问到的频率大致做了一个标注.一颗星表示知识点需要了解,被问到的频率不高,面试时起码能说个差不多.两颗 ...

  3. 一文搞懂RAM、ROM、SDRAM、DRAM、DDR、flash等存储介质

    一文搞懂RAM.ROM.SDRAM.DRAM.DDR.flash等存储介质 存储介质基本分类:ROM和RAM RAM:随机访问存储器(Random Access Memory),易失性.是与CPU直接 ...

  4. 基础篇|一文搞懂RNN(循环神经网络)

    基础篇|一文搞懂RNN(循环神经网络) https://mp.weixin.qq.com/s/va1gmavl2ZESgnM7biORQg 神经网络基础 神经网络可以当做是能够拟合任意函数的黑盒子,只 ...

  5. 一文搞懂 Prometheus 的直方图

    原文链接:一文搞懂 Prometheus 的直方图 Prometheus 中提供了四种指标类型(参考:Prometheus 的指标类型),其中直方图(Histogram)和摘要(Summary)是最复 ...

  6. Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!

    本文原作者: Wizey,作者博客:http://wenshixin.gitee.io,即时通讯网收录时有改动,感谢原作者的无私分享. 1.引言 典型的Web端即时通讯技术应用场景,主要有以下两种形式 ...

  7. 一文搞懂vim复制粘贴

    转载自本人独立博客https://liushiming.cn/2020/01/18/copy-and-paste-in-vim/ 概述 复制粘贴是文本编辑最常用的功能,但是在vim中复制粘贴还是有点麻 ...

  8. 三文搞懂学会Docker容器技术(中)

    接着上面一篇:三文搞懂学会Docker容器技术(上) 6,Docker容器 6.1 创建并启动容器 docker run [OPTIONS] IMAGE [COMMAND] [ARG...] --na ...

  9. 三文搞懂学会Docker容器技术(下)

    接着上面一篇:三文搞懂学会Docker容器技术(上) 三文搞懂学会Docker容器技术(中) 7,Docker容器目录挂载 7.1 简介 容器目录挂载: 我们可以在创建容器的时候,将宿主机的目录与容器 ...

随机推荐

  1. php生成html静态文件

    现在的动态网站存在很多性能上的弊端,seo优化会存在一定的瓶颈,现在将动态的网站代码转换为html静态文件,是浏览器通过html间接的读取动态网站源文件,这对其网站加载速度还是seo优化有着举足轻重的 ...

  2. Java系统架构师学习体系图

  3. Mybatis_two

    SqlMapConfig.xml配置文件 SqlMapConfig.xml中配置的内容和顺序如下: properties(属性) settings(全局配置参数) typeAliases(类型别名) ...

  4. Scala 学习之路(四)—— 数组Array

    一.定长数组 在Scala中,如果你需要一个长度不变的数组,可以使用Array.但需要注意以下两点: 在Scala中使用(index)而不是[index]来访问数组中的元素,因为访问元素,对于Scal ...

  5. Linux实例/etc/fstab文件配置错误导致系统启动异常

    Centos 7.3系统 问题现象: 阿里云ECS升级配置后重启,SSH连接不上.登录控制台远程连接ECS,出现以下界面.  提交工单阿里云反馈:https://help.aliyun.com/kno ...

  6. zabbix2.4汉化

    zabbix的2.4版本安装完后,这里的语言界面选择没有中文,其实是这个版本把中文的屏蔽了. [root@zabbix-server opt]# vim /var/www/html/include/l ...

  7. centos7搭建基于SAMBA的网络存储

    学习目标: 通过本实验理解Linux系统下SAMBA服务器和客户端的配置,实现客户机可自动挂载服务端的共享存储. 操作步骤: 1.  SAMBA服务器搭建 2.  SAMBA客户端配置 参考命令:   ...

  8. cookie 和 session 设置

    cookie: 保存在浏览器上的一组键值对, 是由服务器让浏览器进行设置的 下次浏览器访问的时候会携带cookie. request是客户端请求, response是服务端响应. 读取客户端的cook ...

  9. django实战仿慕课网在线视频网站(完成了85%以上的功能已上传github:https://github.com/huwei86/mxonline):

    1. 前台功能模块 基本模块:登录 注册 找回密码 / 全局搜索 / 个人中心, 课程功能:课程管理 / 讲师管理 / 授课机构管理  热门推荐 相关课程推荐 用户操作管理:用户收藏 / 课程评论   ...

  10. 侦听器watch 监听单个属性

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...