Java泛型:List<?>与List的区别
为什么说List<?>是type-safe而List不是type-safe的?
1、List<?>
compiler看到了你使用了wildcard ?,那么相当于你对compiler说:“我不知道这个List里面的element的runtime-type是什么,如果我尝试对这个list或者list中取出来的object做一些type-specific的操作,你要给我一个compile-time-error来提醒我”。这样就导致了2个结果:
1.1 list.get()返回类型为?,所以你只能用Object接收,Object足以确保type-safe,因为java中任何class都是Object的subclass。(当然,如果你非要使用类型强制转换,转换成什么阿猫阿狗的class,也没人拦得住你,对此只能说“编译器尽力了,你行你上啊”,反正ClassCastException什么的最有爱了)
2.2 list.put()除了null以外,任何参数都不接收。这也足以确保list中类型的type-safe,要知道,java的泛型的implementation是基于ERASURE(擦除)的,举个具体的例子,LinkedList<E>的内部数据结构肯定是基于Node<E>,那么一个Node有2个field,E element和Node<E> next,而实际上在runtime环境中,LinkedList<String>中的Node并不是Node<String>,仅仅是Node,Node里面的element的类型也不是String,仅仅是Object,也就是说,compile-time的type-information都被抹除了(Quote: For backward-compatibility)。试想这么一个情景,Tom传了一个List<Dog>给Mike,Mike的interface是List<?>,Mike往list中放了一个Cat(假设compiler没有阻止Mike),然后Tom取出该List中所有的object并当成Dog使用(compiler会自动加上类型转换的代码——which is how java generics worked),然后Tom就悲剧地得到了一个ClassCastException——这就是为什么除了null其他参数都不接收的原因——阻止Mike随便放东西进去。
2、List
raw-type就是这么个情况,相当于你对compiler说:“我并不在乎这个List里面的element的runtime-type是什么,不管我怎么操作这个list或者list中取出来的object,你都别管,实在看不过去就给我个warning就行了”。这种情况下:
2.1 list.get()返回类型为Object,当然,也是type-safe的(如果你不强制转换的话)
2.2 list.put()的参数类型为Object,也就是说,你爱往里面放什么object就放什么object,还是上面那个例子,就算Tom给Mike的是List<String>,但由于Mike的interface是List,所以Mike放个BigInteger甚至什么Cat、Dog,compiler都不会阻止Mike(但是,要知道,Mike是无法得知其他人会怎么使用这个List的,比如说Mike无法得知Tom相信编译器确保了list中的object都是String,但是由于Mike的raw-type interface,Tom就难免吃ClassCastException咯)
举个具体的例子:

class Dog {
public void bark() {
}
} class Cat {
public void meow() {
}
} public class Foo { public static void foo1(List<?> list) { // Java generics are implemented upon ERASURE, so the runtime-type of elements in List<?> and List are both Object.
if (list.isEmpty()) {
return;
}
Object o = list.get(0); // Type safe if you don't do DOWN-CAST
// list.add(new Dog()); // Won't compile
}
public static void foo2(List list) {
if (list.isEmpty()) {
return;
}
Object o = list.get(0); // Type safe if you don't do DOWN-CAST
list.add(new Cat()); //! Compiler won't stop you, just gives you a little complaint
}
public static void main(String[] args) {
List<Cat> cats = new LinkedList<Cat>();
cats.add(new Cat());
List<Dog> dogs = new LinkedList<Dog>();
dogs.add(new Dog()); foo1(cats); // relatively type-safe
foo2(dogs); // dangerous for (Cat cat : cats) { // Cast from Object to Cat
cat.meow();
} for (Dog dog : dogs) { //! Cast from Object to Dog, ClassCastException
dog.bark();
}
}
}

Java泛型:List<?>与List的区别的更多相关文章
- Java泛型中<? extends E>和<? super E>的区别
这篇文章谈一谈Java泛型声明<? extends E>和<? super E>的作用和区别 <? extends E> <? extends E> 是 ...
- java 泛型E T ?的区别
Java泛型中的标记符含义: E - Element (在集合中使用,因为集合中存放的是元素) T - Type(Java 类) K - Key(键) V - Value(值) N - Number ...
- [转]JAVA泛型通配符T,E,K,V区别,T以及Class<T>,Class<?>的区别
原文地址:https://www.jianshu.com/p/95f349258afb 1. 先解释下泛型概念 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被 ...
- JAVA泛型通配符T,E,K,V区别,T以及Class<T>,Class<?>的区别
1. 先解释下泛型概念 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛 ...
- Java泛型中extends和super的区别?
<? extends T>和<? super T>是Java泛型中的"通配符(Wildcards)"和"边界(Bounds)"的概念. ...
- 浅谈Java泛型之<? extends T>和<? super T>的区别
关于Java泛型,这里我不想总结它是什么,这个百度一下一大堆解释,各种java的书籍中也有明确的定义,只要稍微看一下就能很快清楚.从泛型的英文名字Generic type也能看出,Generic普通. ...
- 初识java泛型
1 协变数组类型(covariant array type) 数组的协变性: if A IS-A B then A[] IS-A B[] 也就是说,java中的数组兼容,一个类型的数组兼容他的子类类型 ...
- Java深度历险(五)——Java泛型
作者 成富 发布于 2011年3月3日 | 注意:QCon全球软件开发大会(北京)2016年4月21-23日,了解更多详情!17 讨论 分享到:微博微信FacebookTwitter有道云笔记邮件 ...
- Java泛型-内部原理: 类型擦除以及类型擦除带来的问题
一:Java泛型的实现方法:类型擦除 大家都知道,Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,正确理解泛型概念的首要前提是理解类型擦除.Java的泛型基本上都是在编译 ...
- java 深度探险 java 泛型
Java泛型(generics)是JDK 5中引入的一个新特性,允许在定义类和接口的时候使用类型参数(type parameter).声明的类型参数在使用时用具体的类型来替换.泛型最主要的应用是在JD ...
随机推荐
- Oracle 未能加载文件或程序集Oracle.DataAccess
原文地址;https://www.cnblogs.com/xuekai-to-sharp/p/3586071.html 关键是引用DLL:Oracle.DataAccess.dll DLL文件的路径: ...
- 吴裕雄 python 机器学习-KNN算法(1)
import numpy as np import operator as op from os import listdir def classify0(inX, dataSet, labels, ...
- RPN(region proposal network)之理解
在faster-r-cnn 中,因为引入rpn层,使得算法速度变快了不少,其实rpn主要作用预测的是 “相对的平移,缩放尺度”,rpn提取出的proposals通常要和anchor box进行拟合回归 ...
- Oracle 监听器日志解析
Oracle监听器是驻留在Oracle实例所在服务器上的独立进程.作为客户端进程连接实例的重要沟通组件,Oracle监听器扮演着重要的地位.本篇将从监听器日志入手,分析阅读监听器日志和日常监听器常见行 ...
- KADEMLIA算法学习
在上一篇文章中<P2P技术是什么>,我们介绍了P2P技术的特点以及发展历史.在本篇文章中,我们来介绍某一个具体的算法. 如今很多P2P网络的实现都采用DHT的方式实现查找,其中Kademl ...
- windows的cmd下面格式化某个盘符
1.crl+R 输入cmd回车. 2.如果要格式化的是E盘,哪直接输入 在DOS窗口中输入“format f: “ ,其中:format 为格式化命令,f: 为需要格式化的分区
- spring boot springmvc视图
pring boot 在springmvc的视图解析器方面就默认集成了ContentNegotiatingViewResolver和BeanNameViewResolver,在视图引擎上就已经集成自动 ...
- python全栈开发 随笔 'is' 和 == 的比较知识与区别 编码和解码的内容及转换
python 一. is 和 == 的区别; == 比较的是两边的值. a = 'alex' b = 'alex' print(a = b) #True a = 10 b = 10 print(a = ...
- centos 7.3+nginx+jira(.bin)+mysql
JIRA 安装参考资料 http://www.cnblogs.com/ilanni/p/6200875.html 注意服务启动与关闭 service jira stop service jira st ...
- 进程实时监控pidstat命令详解
pidstat主要用于监控全部或指定进程占用系统资源的情况,如CPU,内存.设备IO.任务切换.线程等.pidstat首次运行时显示自系统启动开始的各项统计信息,之后运行pidstat将显示自上次运行 ...