Java泛型中? 和 ? extends Object的异同分析
点击上方蓝色“程序猿DD”,选择“设为星标”
回复“资源”获取独家整理的学习资料!
作者 | 刘一手
来源 | 公众号「锅外的大佬」
Java Generics – <?> vs <? extends Object>
相信很多人和我一样,接触Java多年,却仍旧搞不清楚 Java
泛型中 <?>
和 <? extends Object>
的相似和不同。但是,这应该是一个比较高端大气上档次的Question, 在我们进行深入的探讨之前,有必要对Java泛型有一个基础的了解。如果还不了解的,请看上一篇文章!
上一篇文章地址:(http://mp.weixin.qq.com/s?__biz=MzIzNzYxNDYzNw==&mid=2247484950&idx=1&sn=688f958d6f343ee2e314a724ee1129a3&chksm=e8c4a554dfb32c421bb1ac3e0fd461d997d82b68ffc8ea41367a71d537df4a7455af5810e3f4&scene=21#wechat_redirect)
1. 泛型产生的背景
在 JDK5 中引入了泛型来消除编译时错误和加强类型安全性。这种额外的类型安全性消除了某些用例中的强制转换,并使程序员能够编写泛型算法,这两种方法都可以生成更具可读性的代码。
例如,在 JDK5 之前,我们必须使用强制转换来处理列表的元素。这反过来又产生了一类特定的运行时错误:
List aList = new ArrayList();
aList.add(new Integer(1));
aList.add("a_string");for (int i = 0; i < aList.size(); i++) {Integer x = (Integer) aList.get(i);
}
现在,我们想解决两个问题:
我们需要一个显式转换来从
aList
中提取值——类型取决于左侧的变量类型(在本例中为Integer)当我们试图将
a_string
转换为Integer
时,在第二次迭代中会出现运行时错误。
泛型填补了这个空白,代码如下:
List<Integer> iList = new ArrayList<>();
iList.add(1);
iList.add("a_string"); // compile time errorfor (int i = 0; i < iList.size(); i++) {int x = iList.get(i);
}
执行上述代码,编译器会告诉我们,无法将 a_string 添加到 Integer 类型的 List 中,这比起在运行时才发现异常要好很多。而且,不需要显式转换,因为编译器已经知道 iList 包含 Integer类型的数据。另外,由于自动拆箱的关系,我们甚至不需要使用 Integer 类型,它的原始类型就足够了。
2. 泛型中的通配符
问号或通配符在泛型中用来表示未知类型。它可以有三种形式:
无界通配符:List<?> 表示未知类型的列表
上界通配符:List<? extends Number> 表示 Number 或其子类型(如Integer和Double)的列表
下界通配符:List<? super Integer> 表示Integer或其超类型Number和Object的列表
由于 Object 是 Java 中所有类型的固有超类,所以我们会认为它也可以表示未知类型。换句话说,List<?>
和List<Object>
可以达到相同的目的。但事实并非如此。
来看看这两个方法:
public static void printListObject(List<Object> list) { for (Object element : list) { System.out.print(element + " "); }
} public static void printListWildCard(List<?> list) { for (Object element: list) { System.out.print(element + " "); }
}
给出一个整数的列表,比如:
List<Integer> li = Arrays.asList(1, 2, 3);
执行 printListObject(li)
不会编译,并且我们将得到以下错误:
The method printListObject(List<Object>) is not applicable for the arguments (List<Integer>)
而执行 printListWildCard(li)
将通过编译,并将 1 2 3 输出到控制台。
3. <?>和<? extends Object>的相同之处
在上面的示例中,如果我们将 printListWildCard 方法更改为:
public static void printListWildCard(List<? extends Object> list)
它的工作方式与 printListWildCard(List<?>)
相同。这是因为 Object 是 Java 所有对象的超类,基本上所有的东西都扩展了Object。因此,这个方法也会处理一个 Integer 类型的List。
也就是说, <?> 和 <? extends Object> 在这个例子中是同一个意思。
虽然在大多数情况下,这是正确的,但也有一些区别。接下来我们就来看看它们之间的差异。
4. <?>和<? extends Object>的不同之处
可重构类型是指那些在编译时未被擦除的类型。换句话说,一个不可重构类型,运行时将比编译时表达的信息更少,因为其中一些信息会被擦除。
一般来说,参数化类型是不可重新定义的。比如 List<String>
和 Map<Integer,String>
就不可重新定义。编译器会擦除它们的类型,并将它们分别视为列表和映射。
这个准则的唯一例外是无界通配符类型。也就是说, List<?>
以及 Map<?, ?>
是可重写的。
另外,List<? extends Object>
不可重写。虽然微妙,但这是一个显著的区别。
不可重构的类型在某些情况下不能使用,例如在 instanceof
运算符或作为数组的元素。
所以,如果我们的代码写成这样:
List someList = new ArrayList<>();
boolean instanceTest = someList instanceof List<?>
代码编译后,instanceTest 为true。但是,如果我们在 List<? extends Object>
上使用 instanceof 运算符:
List anotherList = new ArrayList<>();
boolean instanceTest = anotherList instanceof List<? extends Object>;
那么第2行不编译。类似地,在下面的代码片段中,第1行编译,但第2行不编译:
List<?>[] arrayOfList = new List<?>[1];
List<? extends Object>[] arrayOfAnotherList = new List<? extends Object>[1]
好了,文章到此就划上句号了,在本文中,我们主要讨论了<?> 和 <? extends Object>的异同,虽然基本上是相似的,但两者在可变与否方面存在细微差异。
DD自研的沪牌代拍业务,点击直达
【往期推荐】
索赔 100 万!只是因为一个开源插件?
2020-11-21
快速搞懂监控、链路追踪、日志三者的区别
2020-11-21
读完《Effective Java》后,总结了 50 条开发技巧
2020-11-20
35岁之后,你还会继续写代码吗?
2020-11-19
11月全国招程序员34万人,猜猜平均工资是多少?
2020-11-18
扫一扫,关注我
一起学习,一起进步
每周赠书,福利不断
﹀
﹀
﹀
深度内容
推荐加入
Java泛型中? 和 ? extends Object的异同分析相关推荐
- Java泛型中extends T和super T的区别?
<? extends T>和<? super T>是Java泛型中的"通配符(Wildcards)"和"边界(Bounds)"的概念. ...
- Java泛型中extends和super的理解(转)
E – Element (在集合中使用,因为集合中存放的是元素) T – Type(Java 类) K – Key(键) V – Value(值) N – Number(数值类型) ? – 表示不确定 ...
- Java泛型中extends和super的区别?
区别 <? extends T>和<? super T>是Java泛型中的"通配符(Wildcards)"和"边界(Bounds)"的概 ...
- 聊一聊Java 泛型中的通配符 T,E,K,V,?
点击上方"方志朋",选择"设为星标" 回复"1024"获取独家整理的学习资料 作者:glmapper juejin.im/post/5d57 ...
- 聊一聊-JAVA 泛型中的通配符 T,E,K,V,?
前言 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许开发者在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所操作的数据 ...
- Java泛型中的PECS原则
今天在写代码的时候使用到了这样一个方法签名: public void foo(Map<String, String> map); 在写这个参数的时候正好在想一些关于泛型的东西,于是: pu ...
- JAVA 泛型中的通配符 T,E,K,V,?
点击上方"朱小厮的博客",选择"设为星标" 后台回复"加群",加入新技术 来源:8rr.co/2Xqx 前言 Java 泛型(generic ...
- 一文读懂Java泛型中的通配符 ?
之前不太明白泛型中通配符"?"的含义,直到我在网上发现了Jakob Jenkov的一篇文章,觉得很不错,所以翻译过来,大家也可以点击文末左下角的阅读原文看英文版的原文. 下面是我的 ...
- 原神一面:Java 泛型中的通配符 T,E,K,V,?,你确定都了解吗?
点击上方 "编程技术圈"关注, 星标或置顶一起成长 后台回复"大礼包"有惊喜礼包! 每日英文 Sometimes, the same thing, we can ...
最新文章
- [置顶] JDK工具(零)--简要介绍JDK1.6自带的42个工具
- 双网卡绑定之负载均衡高可用(bond)
- linux ftp上传下载文件,Linux下ftp命令上传下载文件
- tornado 学习笔记17 HTTPServerRequest分析
- Unity3D性能优化
- Linux学习总结(八)-磁盘格式化,挂载,swap扩容
- org.springframework.web.client.RestClientException: Could not extract response
- 从“救火”到“井然有序”
- socket编程详解,转自http://www.sme-cn.com:82/archives/669
- STM32固件库下载步骤
- mysql批量sql语句 c_Mysql批量插入数据sql语句
- 报计算机用几寸照片,在电脑显示的2寸照片的大小是几×几?
- Windows10 LTSB/LTSC 企业版安装应用商店
- Docker安装与镜像的使用
- USB OTG(Host) 、 USB ADB(Device)、DWC3 Charge
- 哈工大软件过程与工具复习5——第9讲 软件设计
- 函数柯里化与反柯里化
- 直接插入法(java实现)
- 2008 r2服务器日志文件,Windows2008R2共享文件访问日志查询的设置方法
- 【JZOJ】【匈牙利算法】【二分】 导弹
热门文章
- 很高兴加入51cto——交朋友
- docker 容器 defunct 僵尸进程
- windows下使用自带certutil工具校验文件MD5、SHA1、SHA256
- centos transmission 无法开启登录验证
- linux c 执行shell命令并获取返回结果
- 遍历创建进程、创建线程、加载模块的回调函数
- 在本机快速创建YUM源
- 利用 libvirt 和 Linux 审计子系统跟踪 KVM 客户机
- 数字媒体技术和数据科学与大数据技术_?数据科学与大数据技术的就业前景和待遇怎么样?...
- 湘潭大学网络编程_湘潭大学计算机学院网络空间安全学院“湘韵”研究生论坛成功举行...