前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >泛型容器Collection

泛型容器Collection

作者头像
tiaotiaoba
发布于 2022-01-18 02:14:37
发布于 2022-01-18 02:14:37
47400
代码可运行
举报
文章被收录于专栏:跳跳爸的Abc跳跳爸的Abc
运行总次数:0
代码可运行

今天简单聊聊java泛型之:

  • Collection<Number>
  • Collection<? extends Number>
  • Collection<?>
  • Collection<Object>

先简单来段例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void testGenerics() {
    Collection<Number> numbers = new ArrayList<>();
    numbers.add(1); // ok
    numbers.add(0.1); // ok

    Collection<? extends Number> numbers2 = new ArrayList<>();
    // don't work, you don't know which subtype 'numbers2' exactly contains
    numbers2.add(1); // oops!
}

这个例子其实有点反人类,估计大部分人(包括我)对这种转换的第一反应肯定是“当然是对的”(这就掉坑了),说下我的理解:

  • Collection<Number>:表示这个Collection里包含的都是Number类型的对象,可以是Integer/Long/Float,因为编译器可以判断obj instanceof Number == true;
  • Collection<? extends Number>:表示这个Collection是Number类型的“某个子类型”的Collection实例,可以是Collection<Integer>/Collection<Long>,所以调用numbers2.add(1)是不行的,因为编译器不知道这个numbers2包含的元素到底是Number的哪个子类型,编译器无法判断obj instanceof UnknownType的结果;
  • Collection<E>,这个E类型是“一个”具体的类型,而不能是表示某个parent的多种子类型的占位符;

再来个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void testGenerics() {
    Collection<Number> numbers = new ArrayList<>();
    Collection<Integer> integers = new ArrayList<>();
    Collection<? extends Number> numbers2 = new ArrayList<>();
    
    numbers2 = integers; // ok
    numbers2 = numbers; // ok
    
    // don't work, Collection<Number> != Collection<Integer>
    numbers = integers; // oops!
}

Integer明明继承了Number,那为什么

  • Collection<Number> == Collection<Integer>

不成立呢,我们再来看个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void testGenerics() {
    Collection<Integer> profits = new ArrayList<>();
    
    insertSomething(profits); // line 1
    
    Integer profit = profits.iterator().next(); // oops! crash
}

private void insertSomething(Collection<Number> numbers) {
    numbers.add(Long.MAX_VALUE);
}

如果line 1成立,那么接下去获取利润将会得到个负数,后续的一系列计算都会发声异常,如果代码不够健壮甚至可能会抛出一些意料之外的RuntimeException,导致方法不正常结束甚至程序crash。

所以一句话,Collection<Number> != Collection<Integer>是为了运行期的安全,将可能发生的类型转换异常在编译期就解决掉。

现在再来说说Collection<Object>与Collection<?>,又是很多人(包括我)第一反应肯定是“Object是所有java对象的公共父类,所以Collection<Object>可以表示任意类型的集合”,来看个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void testGenerics2() {
    Collection<Integer> integers = new ArrayList<>();

    Collection<?> objects2 = integers; // ok
    // don't work, which type of 'objects2' contains is uncertain
    objects2.add(1); // oops!
    
    Collection<Object> objects = integers; // oops!
}
  • Collection<?>表示的范围比Collection<Object>大;
  • 无法调用objects2.add(1)是因为编译器无法精确推断objects2到底是哪种数据类型的容器,可能会产生运行时的类型转换异常;
  • 表示任意数据类型集合的正确写法是Collection<?>;
  • Collection<Object>不能表示任意类型的集合。

为什么Collection<Object>不是表示任意类型的集合呢,其实也是编译器认为这里有类型转换错误的风险:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void testGenerics() {
    Collection<Integer> integers = new ArrayList<>();

    Collection<Object> objects = integers; // oops!
    // don't work, which type of 'objects2' contains is uncertain
    objects.add("1");

    Integer one = objects.iterator().next(); // oops! crash
}
  • Collection<Object>是可以往容器add数据的,因为Object是所有对象的父类,是已知类型,可以用obj instanceof Object判断;
  • Collection<?>不能往容器放数据,因为? (UnknownType)是未知类型,无法判断obj instanceof UnknownType的结果;
  • ?是表示未知类型,Object表示的是已知类型;
  • 如果Collection<Object>表示任意类型,按照墨菲定律(可能会发生的事必然会发生),那么上面例子中的crash是必然会发生的。。(又是一个线上故障)

后记:

很久没发声了,一直想写点赞搜索架构设计中的小心得,然而才动了几个字,先来点随笔填填空虚。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-08-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 跳跳爸的Abc 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Java】Collection集合&泛型
👀专栏介绍 【Java】 目前主要更新Java,一起学习一起进步。 👀本期介绍 本期主要介绍Collection集合&泛型 文章目录 第一章 Collection集合 1.1 集合概述 1.2 集合框架 1.3 Collection 常用功能 第二章 Iterator迭代器 2.1 Iterator接口 2.2 迭代器的实现原理 2.3 增强for 第三章 泛型 3.1 泛型概述 3.2 使用泛型的好处 3.3 泛型的定义与使用 定义和使用含有泛型的类 含有泛型的方法 含有泛型的接口 3.4 泛型通配符
陶然同学
2023/02/27
5100
【Java】Collection集合&泛型
Java 泛型详细解析
实际使用的时候就可以给这个 T 指定任何实际的类型,比如下面所示,就指定了实际类型为 LocalDate,泛型给了我们一个错觉就是通过个这个模板类 Pair<T>,我们可以在实际使用的时候动态的派生出各种实际的类型,比如这里的 Pair<LocalDate> 类。
javadaysdaysup
2024/12/01
2770
Java 泛型详细解析
Java 泛型
在J2SE 5.0中引入的这个对类型系统期待已久的增强允许类型或方法在提供编译时类型安全性的同时操作各种类型的对象。它将编译时类型安全性添加到集合框架中,并消除了强制转换的繁琐工作。
Erossssssss
2021/04/09
2.3K0
Java 泛型
Collection<Number>与Collection<? extends Number>与Collection<?>
这个问题其实有点反人类,估计大部分人(包括我)对这种转换的第一反应肯定是“当然是对的。。”,说下我的理解:
tiaotiaoba
2022/01/18
4430
深入理解 Java 泛型
泛型要求在声明时指定实际数据类型,Java 编译器在编译时会对泛型代码做强类型检查,并在代码违反类型安全时发出告警。早发现,早治理,把隐患扼杀于摇篮,在编译时发现并修复错误所付出的代价远比在运行时小。
静默虚空
2022/03/23
4220
深入理解 Java 泛型
深入理解 Java 泛型
文章主要介绍了Java中的泛型概念,包括泛型的定义、约束、类型擦除以及原始类型和泛型类型的转换。此外还讲解了在Java中使用泛型的好处以及如何在代码中使用泛型。
张拭心 shixinzhang
2018/01/05
2.2K0
【Java基本功】一文读懂Java中的泛型
本文参考https://blog.csdn.net/s10461/article/details/53941091
Java技术江湖
2019/09/25
4890
(35) 泛型 (上) - 基本概念和原理 / 计算机程序的思维逻辑
之前章节中我们多次提到过泛型这个概念,从本节开始,我们就来详细讨论Java中的泛型,虽然泛型的基本思维和概念是比较简单的,但它有一些非常令人费解的语法、细节、以及局限性,内容比较多。 所以我们分为三节,逐步来讨论,本节我们主要来介绍泛型的基本概念和原理,下节我们重点讨论令人费解的通配符,最后一节,我们讨论一些细节和泛型的局限性。 后续章节我们会介绍各种容器类,容器类可以说是日常程序开发中天天用到的,没有容器类,难以想象能开发什么真正有用的程序。而容器类是基于泛型的,不理解泛型,我们就难以深刻理解容器类。那,
swiftma
2018/01/31
7830
Java 泛型进阶
在 List<String> 中添加 Integer 将不会通过编译,但是List<Sring>与List<Integer>在运行时的确是同一种类型。
yuxiaofei93
2018/09/11
8090
重学Java之泛型的基本使用
本身是打算接着写JMM、JCStress,然后这两个是在公司闲暇的时候随手写的,没有推到Github上,但写点什么可以让我获得宁静的感觉,所性就从待办中拎了一篇文章,也就是这篇泛型。这篇文章来自于我朋友提出的一个问题,比如我在一个类里面声明了两个方法,两个方法只有返回类型是int,一个是Integer,像下面这样,能否通过编译:
阿珍
2023/05/04
3760
聊聊JDK泛型那些事儿
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。 
孟君
2019/08/28
3710
聊聊JDK泛型那些事儿
掌握8条泛型规则,打造优雅通用的Java代码
如果在添加对象时,不小心将不同类型的对象加入集合,那么获取对象强制转换时会发生报错
菜菜的后端私房菜
2024/07/26
771
游刃有余:玩转Java泛型
Java 中的泛型提供了一种创建可以处理不同类型数据的可重用代码的方法。它允许用户定义可操作各种数据类型的类、接口和方法,而无需牺牲类型安全性。在 Java 5 中引入的泛型已经成为 Java 编程语言的一个基本特性。
FunTester
2023/12/19
1610
游刃有余:玩转Java泛型
泛型的基本原理
泛型是 JDK1.5 的一个新特性,其实就是一个『语法糖』,本质上就是编译器为了提供更好的可读性而提供的一种小「手段」,虚拟机层面是不存在所谓『泛型』的概念的。
Single
2018/07/31
5780
泛型的基本原理
(36) 泛型 (中) - 解析通配符 / 计算机程序的思维逻辑
上节我们介绍了泛型的基本概念和原理,本节继续讨论泛型,主要讨论泛型中的通配符概念。通配符有着令人费解和混淆的语法,但通配符大量应用于Java容器类中,它到底是什么?本节,让我们逐步来解析。 更简洁的参数类型限定 在上节最后,我们提到一个例子,为了将Integer对象添加到Number容器中,我们的类型参数使用了其他类型参数作为上界,代码是: public <T extends E> void addAll(DynamicArray<T> c) { for(int i=0; i<c.size; i
swiftma
2018/01/31
6960
【Java 基础篇】Java Collection 详解:集合入门指南
Java 是一种流行的编程语言,其中的集合(Collection)框架为处理和操作数据提供了丰富的工具。无论你是刚刚开始学习 Java,还是已经有一些经验,理解如何使用集合是非常重要的,因为它们是 Java 程序中最常用的数据结构之一。本篇博客将向你介绍 Java 中的 Collection 集合,包括什么是集合、为什么需要它们以及如何使用它们。
繁依Fanyi
2023/10/12
1.8K0
【Java 基础篇】Java Collection 详解:集合入门指南
第8章 泛型第8章 泛型
通常情况的类和函数,我们只需要使用具体的类型即可:要么是基本类型,要么是自定义的类。但是在集合类的场景下,我们通常需要编写可以应用于多种类型的代码,我们最简单原始的做法是,针对每一种类型,写一套刻板的代码。这样做,代码复用率会很低,抽象也没有做好。我们能不能把“类型”也抽象成参数呢?是的,当然可以。
一个会写诗的程序员
2018/08/17
1.9K0
第8章 泛型第8章 泛型
java基础之泛型
泛型 术语 "?"通配符 通配符的扩展 自定义泛型方法 "擦除"实例 类型参数的类型推断 自定义泛型类 泛型方法和泛型类的比较 泛型和反射 通过反射获得泛型的实际类型参数 本文对泛型的基本
xiangzhihong
2018/02/01
1.1K0
java基础之泛型
Kotlin入门潜修之类和对象篇—泛型及其原理
如果我们了解java中的泛型,那么本篇文章提到的kotlin泛型我们也不会陌生。但是如果之前没有接触过泛型或者没有真正理解泛型,本篇文章理解起来可能有些困难,不过我会尽量阐述的通俗易懂。
Android架构
2019/06/24
9420
Java 泛型
本文介绍了Java中的泛型机制,主要包括泛型的定义、泛型类型的变量、泛型方法以及通配符等内容。同时,还讲解了在 Java 中如何使用泛型,以及需要注意的一些问题。
IT可乐
2018/01/04
1.6K0
Java 泛型
相关推荐
【Java】Collection集合&泛型
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文