List和List的区别?
List<T>和List<?>的区别,这问的有点含糊。我想题主是想问类型参数“<T>”和无界通配符“<?>”的区别吧?
讨论“<T>"和"<?>",首先要区分开两种不同的场景:
- 第一,声明一个泛型类或泛型方法。
- 第二,使用泛型类或泛型方法。
类型参数“<T>”主要用于第一种,声明泛型类或泛型方法。
无界通配符“<?>”主要用于第二种,使用泛型类或泛型方法。
1. <T>声明泛型类的类型参数
List<T>最应该出现的地方,应该是定义一个泛型List容器。但List是库里自带的容器,看看ArrayList的源码头一行:
- public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.o.Serializable {
- ... ...
- }
ArrayList<E>中的“E”也是类型参数。只是表示容器中元素Element的时候,习惯用“E”。换一个简单的例子,我们自己定义一个新泛型容器叫Box<T>。
- class Box<T>{
- private T item1;
- private T item2;
- }
为什么这里要用类型参数?因为这是一种”约束“,为了保证Box里的item1, item2都是同一个类型T。Box<String>,代表两个item都是String。Box<Integer>里两个item都是Integer。
List容器库里都帮我们写好了,所以我们是不会去定义List<T>的。
那什么时候会出现List<T>?有几种情况,
要么是作为泛型类的成员字段或成员方法的参数间接出现。还是刚才Box<T>的例子,
- class Box<T>{
- private List<T> item;
- public List<T> get(){return item;}
- public void set(List<T> t){item=t;}
- }
现在Box类里有三个地方出现了List<T>:
- 成员字段item的类型
- get( )方法的返回值
- set( )方法的参数
这里写成List<T>为了表示和Box<T>类型参数保持一致。
2. <T>声明泛型方法
另外一种会出现List<T>的地方是泛型方法。比如Function类的reduce是个静态泛型方法,负责对列表里的所有元素求和。这里的List<T>出现在参数,函数返回值和函数内部,也是为了保持泛型类型的一致性。
- class Fuction{
- public static <T> List<T> reduce(List<T> list){
- //...do something
- }
- }
3. 无界通配符<?>不能当“类型参数”用
反观List<?>,首先要明确通配符不能拿来声明泛型。像下面这样用通配符"?"来表示类型参数的约束是肯定不行的。
- //Error Example
- class Box<?>{
- private ? item1;
- private ? item2;
- }
所以通配符是拿来使用定义好的泛型的。比如声明List容器的一个实例对象。
List<?> list = new ArrayList<String>();
4. <?>的各种坑
但List<?>这个写法非常坑。因为,这时候通配符会捕获具体的String类型,但编译器不叫它String,而是起个临时的代号,比如”CAP#1“。所以以后再也不能往list里存任何元素,包括String。唯一能存的就是null。
- List<?> list = new ArrayList<String>();
- list.add("hello"); //ERROR
- list.add(111); //ERROR
- //argument mismatch; String cannot be converted to CAP#1
- //argument mismatch; int cannot be converted to CAP#1
另外如果拿List<?>做参数,也会有奇妙的事情发生。还是刚才Box<T>的例子,有get()和set()两个方法,一个存,一个取。
- class Box<T>{
- private List<T> item;
- public List<T> get(){return item;}
- public void set(List<T> t){item=t;}
- //把item取出来,再放回去
- public void getSet(Box<?> box){box.set(box.get());} //ERROR
- }
新的getSet()方法,只是把item先用get()方法读出来,然后再用set()方法存回去。按理说不可能有问题。实际运行却会报错。
error: incompatible types: Object cannot be converted to CAP#1
原因和前面一样,通配符box<?>.set()的参数类型被编译器捕获,命名为CAP#1,和box<?>.get()返回的Object对象无法匹配。
解决方法,是要给getSet()方法写一个辅助函数,具体原理可以去查《Java核心技术-卷1》,泛型这章,或者《Java编程思想》。都有讲。
- class Box<T>{
- private List<T> item;
- public List<T> get(){return item;}
- public void set(List<T> t){item=t;}
- //helper()函数辅助getSet()方法存取元素
- public void getSet(Box<?> box){helper(box);}
- public <V> void helper(Box<V> box){box.set(box.get());}
- }
5. 有界通配符<? extends XXX>,<? super XXX>
List和List的区别?的更多相关文章
- c#与java的区别
经常有人问这种问题,用了些时间java之后,发现这俩玩意除了一小部分壳子长的还有能稍微凑合上,基本上没什么相似之处,可以说也就是马甲层面上的相似吧,还是比较短的马甲... 一般C#多用于业务系统的开发 ...
- jquery和Js的区别和基础操作
jqery的语法和js的语法一样,算是把js升级了一下,这两种语法可以一起使用,只不过是用jqery更加方便 一个页面想要使用jqery的话,先要引入一下jqery包,jqery包从网上下一个就可以, ...
- 【原】nodejs全局安装和本地安装的区别
来微信支付有2年多了,从2年前的互联网模式转变为O2O模式,主要的场景是跟线下的商户去打交道,不像以往的互联网模式,有产品经理提需求,我们帮忙去解决问题. 转型后是这样的,团队成员更多需要去寻找业务的 ...
- 探究@property申明对象属性时copy与strong的区别
一.问题来源 一直没有搞清楚NSString.NSArray.NSDictionary--属性描述关键字copy和strong的区别,看别人的项目中属性定义有的用copy,有的用strong.自己在开 ...
- X86和X86_64和X64有什么区别?
x86是指intel的开发的一种32位指令集,从386开始时代开始的,一直沿用至今,是一种cisc指令集,所有intel早期的cpu,amd早期的cpu都支持这种指令集,ntel官方文档里面称为&qu ...
- Java中Comparable与Comparator的区别
相同 Comparable和Comparator都是用来实现对象的比较.排序 要想对象比较.排序,都需要实现Comparable或Comparator接口 Comparable和Comparator都 ...
- MySQL中interactive_timeout和wait_timeout的区别
在用mysql客户端对数据库进行操作时,打开终端窗口,如果一段时间没有操作,再次操作时,常常会报如下错误: ERROR (HY000): Lost connection to MySQL server ...
- 设置line-height:1.5和line-height:150%或者line-height:150px的区别
直接正题: 看一下line-height可能的值: 其实可以分为两类: (1)不带单位的(如line-height:1.5),这种是推荐使用的: (2)带单位的(如line-heigth:30px/1 ...
- C#中Length和Count的区别(个人观点)
这篇文章将会很短...短到比你的JJ还短,当然开玩笑了.网上有说过Length和count的区别,都是很含糊的,我没有发现有 文章说得比较透彻的,所以,虽然这篇文章很短,我还是希望能留在首页,听听大家 ...
- select、poll、epoll之间的区别总结
select.poll.epoll之间的区别总结 05/05. 2014 select,poll,epoll都是IO多路复用的机制.I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪 ...
随机推荐
- test20190825 AmberFrame
100+0+99=199,第二题一分没得不应该. count 给定 \(n\),求合法的 \((x_1,x_2,x_3,\dots,x_{2m})\) 组数.一组 \(x\) 是合法的,当且仅当 \[ ...
- CF600E Lomsat gelral 和 CF741D Dokhtar-kosh paths
Lomsat gelral 一棵以\(1\)为根的树有\(n\)个结点,每个结点都有一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号(若有数量一样的,则求编号和). \(n \le 10^ ...
- HDFS中的数据块(Block)
我们在分布式存储原理总结中了解了分布式存储的三大特点: 数据分块,分布式的存储在多台机器上 数据块冗余存储在多台机器以提高数据块的高可用性 遵从主/从(master/slave)结构的分布式存储集群 ...
- RestTemplate将字符串以文件的方式上传
背景 在java后台将内容拼接为字符串,然后使用RestTemplate将字符串以文件的方式上传到指定接口 思路 使用 RestTemplate 时,将字符串封装为字节流,然后上传 代码 /** * ...
- 从零实现jQuery的extend
前言 jQuery 的 extend 是 jQuery 中应用非常多的一个函数,今天我们一边看 jQuery 的 extend 的特性,一边实现一个 extend! extend 基本用法 先来看看 ...
- python - django (ORM使用步骤)
print('asd') """ # 1. 手动创建一个数据库 # 2. 在 Django 项目中设置连接数据库的相关配置(告诉Django 连接哪一个数据库) 在 DA ...
- Spring入门(二)——DI
1. DI Dependency Injection,依赖注入.当对象里有属性或对象的时候,就需要为这些属性或对象赋值 2. 流程 这里介绍两种方式 set方法 注解方式 2.1 set方法 Bean ...
- cube.js 学习(四)cube.js cube 说明
cube 是cube.js data schema 的核心,里面定义了生成sql 的说明 一个比较全的schema 例子 cube(`Users`, { sql: `select * from u ...
- AttributeError: module 'tensorflow' has no attribute 'set_random_seed'
anaconda3 python3.7 安装好tensorflow 后出现上面的问题,原因是安装的tensorflow版本是2.0的,所以使用以前的代码tensorflow中的函数不兼容.
- Leetcode Majority Element系列 摩尔投票法
先看一题,洛谷2397: 题目背景 自动上次redbag用加法好好的刁难过了yyy同学以后,yyy十分愤怒.他还击给了redbag一题,但是这题他惊讶的发现自己居然也不会,所以只好找你 题目描述 [h ...