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 ...
随机推荐
- 18.1利用socket .io 实现 editor间代码的同步
首先,我们想实现在同一个页面editor 大家同时编辑 同步 所以能 我们需要这个url 作为我们 session id 或者叫聊天室的roomid 或者 反正就是保证他们在同一个list里面 就是 ...
- 我理解的BFC(块级格式化上下文)
BFC(Block formatting context) 直译为"块级格式化上下文". BFC它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Bl ...
- 三种方式监听NGUI的事件方法
NGUI研究院之三种方式监听NGUI的事件方法(七) NGUI事件的种类很多,比如点击.双击.拖动.滑动等等,他们处理事件的原理几乎万全一样,本文只用按钮来举例. 1.直接监听事件 把下面脚本直接绑定 ...
- C# HttpWebRequest 错误总结
1.form data 需要编码!!! byte[] data = new ASCIIEncoding().GetBytes("pattern=0&wwid=古兴越&good ...
- Hadoop分布式HA的安装部署
Hadoop分布式HA的安装部署 前言 单机版的Hadoop环境只有一个namenode,一般namenode出现问题,整个系统也就无法使用,所以高可用主要指的是namenode的高可用,即存在两个n ...
- js高级-函数变量提升
var a = 10; function f1(){ console.log(a) //undefined 函数变量提升了 函数执行之前想创建了函数的EC 把函数里面声明的变量初始化undefine ...
- (转载)jenkins 安装 SVN Publisher 后向 svn 提交代码报错: E170001: Authentication required for...
问题描写叙述 安装并启动 jenkins 后,加入了 SVN Publisher 插件,然后在构建任务的“构建后操作”操作中加入了“Publish to Subversion repository”相 ...
- 通过网址request到response经历的过程
前言当我们在浏览器中输入一个网址,比如www.google.cn,浏览器就会加载出百度的主页.那么浏览器背后完成的具体是怎么样的呢? 总结起来大概的流程是这样的: (1)浏览器本身是一个客户端,当你输 ...
- fiddler模拟timeout超时场景
fiddler模拟网络超时: 用fiddler模拟网络请求超时 最近要测试程序对cgi 请求超时的兼容,所以就需要模拟超时,第一个想到的就是fiddler工具,说一下具体的做法: Rules -> ...
- sublime text3的注册码以及常用方法
Michael BarnesSingle User LicenseEA7E-8213858A353C41 872A0D5C DF9B2950 AFF6F667C458EA6D 8EA3C286 98D ...