第二十八条:列表优于数组

news2024/9/9 0:08:32

列表和数组的两个区别:


1、数组是协变的,而泛型则是可变的

协变的意思就是,对于数组,如果 Sub 为 Super 的子类型,那么数组类型 Su[]就是Super[]的子类型。而泛型,List<Sub>不是List<Super>的子类,List<Super>也不是List<Sub>的超类。下面两种代码,数组实现的是合法的,能通过编译器的检验,但是在运行时环境下会报错。而List实现的则不能,即在编译时就回报错。我们更希望不合理的代码在编译时就报错,在运行时报错会增大排查成本。

案例:

    public static void main(String[] args) {
        
        Object[] obj = new Long[10];
        //运行时候报错:java.lang.ArrayStoreException
        obj[0] = "Is right";

        //编译时直接报错
        List<Object> data = new ArrayList<String>();



    }

2、数组和泛型的第二个主要区别在于数组是具体化的。

数组:运行时检验。因为数组在编译时其创建的类是具体化的,在运行期间才检验类型约束是否正确。所以就会产生将String类添加到Long类型的数组中会在运行时报java.lang.ArrayStoreException的错误。感觉这个模式是特定针对数组的协变而创造的,因为数组在编译器中也是会受检验报错的。

创建泛型数组是非法的

优于上述的根本区别,数组和泛型不能很好地混合使用,例如List<E>[ ],new List<String>[ ],new E[ ]都是非法的。

    public static void main(String[] args) {
        // 为什么泛型数组是不合法的----无法编译!
        List <String>[] stringlists =new List<String>[1];
        List<Integer> intlist = List.of(42);
        Object[] objects = stringlists;
        objects[0] = intlist;
        String s = stringlists[0].get(0);



    }

如上述代码假设第(1)行是合法的,(2)是正常的。

(3)行代码中,stringlists是List <String>[]类型的,由于泛型可擦除,stringlists在运行时实际上是List[]的,而数组是协变的,因此(3)不会报错,同理(4)也不会错。

经过(1),(2),(3),(4)行,我们发现,一个List<Integer>的类型的数据被当成stringlists的一个元素,而stringlists是List <String>[]类型的,这行程了严重的堆污染。很明显第(5)行必然会报错。

上述例子展示了泛型数组带来的严重问题,因此泛型数组是非法的。当使用泛型数组出错是,建议考虑使用集合类型List<E>。

当你在强制转换为数组类型时,得到泛型数组创建错误,或是未经检查的强制转换警告时,最佳解决方案通常是使用集合类型 List<E> 而不是数组类型 E[]
这样可能会牺牲一些简洁性或性能,但作为交换,你会获得更好的类型安全性和互操作性。

例子:

public class Chooser<T> {
    private final T[] choiceArray;

    public Chooser(Collection<T> choices) {
        choiceArray = (T[]) choices.toArray();
    }

    public Object choose() {
        Random rnd = ThreadLocalRandom.current();
        return choiceArray[rnd.nextInt(choiceArray.length)];
    }
}

会得到警告

Chooser.java:9: warning: [unchecked] unchecked cast
        choiceArray = (T[]) choices.toArray();
                                           ^
  required: T[], found: Object[]
  where T is a type-variable:
T extends Object declared in class Chooser

编译器告诉你在运行时不能保证强制转换的安全性,因为程序不会知道 T 代表什么类型——因为元素类型信息在运行时会被泛型删除。
该程序可以正常工作吗? 是的,但编译器不能证明这一点。
你可以向自己证明这一点,但是你最好将证据放在注释中,指出消除警告的原因,并使用注解隐藏警告(27):

改为如下即可,不会有警告,在运行时也不会得到 ClassCastException 异常:

public class Chooser<T> {
    private final List<T> choiceList;//数组改为list


    public Chooser(Collection<T> choices) {
        choiceList = new ArrayList<>(choices);
    }


    public T choose() {
        Random rnd = ThreadLocalRandom.current();
        return choiceList.get(rnd.nextInt(choiceList.size()));
    }
}

总而言之,数组和泛型的类型规则有很大的不同。数组是协变和具体化的; 泛型是不变的,而且会被擦除。因此,数组提供运行时类型的安全性,但不提供编译时类型的安全性,反之亦然。一般来说,数组和泛型不能很好地混合工作,数组需要非常多的强转如果发现把它们混合在一起,得到编译时错误或者警告,你的第一个冲动应该是用列表来替换数组。

 所有文章无条件开放,顺手点个赞不为过吧!

                                                                      

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1958149.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何用PostMan按照规律进行循环访问接口

①设置动态变量 步骤一: 设置环境变量 1. 创建环境变量集合 在 Postman 左上角选择 "环境"&#xff0c;然后点击 "添加" 来创建一个新的环境变量集合。给它起一个名称&#xff0c;比如 "uploadDemo". 2. 添加初始变量 在新创建的环境变量集…

校车购票小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;学生管理&#xff0c;我的乘车信息管理&#xff0c;车辆信息管理&#xff0c;座位管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;车辆信息&#xff0c;我的 开发系统…

electron 主进程和渲染进程

最近在整理electron 相关的项目问题&#xff0c;对自己来说也是温故知新&#xff0c;也希望能对小伙伴们有所帮助&#xff0c;大家共同努力共同进步。加油&#xff01;&#xff01;&#xff01;&#xff01; 虽然最近一年前端大环境不好&#xff0c;但是大家还是要加油鸭&#…

kafka leader选举过程浅析

文章目录 概要核心概念leader选举具体流程小结 概要 kafka我们都知道它是通过副本机制&#xff0c;来支持负载均衡和故障转移等高可用的&#xff0c;那么具体副本的选举过程你了解吗&#xff1f;下面我们一起来学习下吧&#xff01; 核心概念 Controller定义&#xff1a;是特…

Cocos Creator2D游戏开发(7)-飞机大战(5)-让子弹飞

飞机大战(5)-碰撞及积分 参考敌机的生成 子弹由飞机生成,放在player_node节点子弹重复使用,要使用预制体;子弹新增了动画 ①创建一个预制体 命名为playerBullet_prefab ② 双击预制体将bullet1图片拖入预制体 保存,关闭(场景编辑器里面的) ③ 发射子弹 player加入代码 prop…

尚庭公寓(五)

图片上传管理 由于公寓、房间等实体均包含图片信息&#xff0c;所以在新增或修改公寓、房间信息时&#xff0c;需要上传图片&#xff0c;因此我们需要实现一个上传图片的接口。 **1. 图片上传流程** 下图展示了新增房间或公寓时&#xff0c;上传图片的流程。 可以看出图片上传…

翻译: 可视化深度学习神经网络二

并甚至在图像识别之外做各种各样智能的东西也许你也想分解成一些抽象的层 例如句子的分析涉及到把原始的语音提出一些独特的声音构成一些音节再构成词再构成词组以及更为抽象的思想等。 但回到这些实际是怎样工作的把你自己现在就放到这个的情景怎样来设计 如何在让这层中的激励…

阿里云主机 安装RabbitMQ

一、操作系统 用的是Alibaba Cloud Linux release 3 (Soaring Falcon)系统&#xff0c;可以通过命令&#xff1a;lsb_release -a 查看系统信息。 二、安装RabbitMQ RabbitMQ 是基于 Erlang 语言构建的&#xff0c;要安装RabbitMQ&#xff0c;需先安装Erlang环境。通过Erlang V…

SearchGPT:搜索引擎市场的潜在游戏规则改变者

关注公众号网络研究观获取更多内容。 OpenAI最近发布的SearchGPT原型标志着搜索技术领域的重大进展。我一直在等待这一天&#xff0c;任何关注搜索和搜索引擎优化领域的人也是如此。我们有充分的理由相信&#xff0c;这一举措很有可能颠覆长期由谷歌等巨头主导的搜索引擎市场&…

宠物医院预约系统-计算机毕业设计源码60818

目录 摘要 Abstract 第一章 绪论 1.1 选题背景及意义 1.2 国内外研究现状 1.3 研究方法 第二章 相关技术介绍 2.1 MySQL简介 2.2 Java编程语言 2.3 B/S模式 2.4 springboot框架 第三章 宠物医院预约系统 系统分析 3.1 系统目标 3.2 系统可行性分析 3.2.1 技术可行…

链式队列实现

归纳编程学习的感悟, 记录奋斗路上的点滴, 希望能帮到一样刻苦的你! 如有不足欢迎指正! 共同学习交流! 🌎欢迎各位→点赞 👍+ 收藏⭐ + 留言​📝唯有主动付出,才有丰富的果实获得收获! 在计算机科学中,队列是一种先进先出(FIFO, First In First Out)的数据结构…

.NET周刊【7月第4期 2024-07-28】

国内文章 .NET 高性能缓冲队列实现 BufferQueue https://mp.weixin.qq.com/s/fUhJpyPqwcmb3whuV3CDyg BufferQueue 是一个用 .NET 编写的高性能的缓冲队列实现&#xff0c;支持多线程并发操作。 项目地址&#xff1a;https://github.com/eventhorizon-cli/BufferQueue 项目…

Robot Operating System——远程修改日志等级

大纲 日志输出Node修改其他Node日志等级的Node获取日志等级设置日志等级 测试默认等级Debug等级Warn等级Error等级 完整代码 在任何系统中&#xff0c;日志功能的重要性都是不容忽视的。日志功能为开发者、维护者甚至用户提供了一个关键的工具&#xff0c;以监控、理解和调试系…

基于Windows Docker desktop搭建pwn环境

安装虚拟机很重&#xff0c;占空间&#xff0c;影响速度。 今天试了下用Windows下的Docker搭建pwn做题环境&#xff0c;搭配MobaXterm真的很好! 一、Windows下安装Docker desktop 网上参考文章很多&#xff0c;不赘述。 说明&#xff1a;去https://www.docker.com/products/d…

PHP经销商订货管理系统小程序源码

经销商订货管理系统&#xff1a;重塑供应链效率的利器 &#x1f680; 开篇&#xff1a;解锁供应链管理的新纪元 在竞争激烈的商业环境中&#xff0c;经销商作为供应链的关键一环&#xff0c;其订货效率直接影响到整个供应链的流畅度和响应速度。传统的订货方式往往繁琐、易出…

【C++深度探索】深入解析AVL树的底层实现机制

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;C从入门至进阶 这里将会不定期更新有关C/C的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 前言 AV…

学习大数据DAY26 简单数据清洗练习和 Shell 脚本中的数据库编程

目录 上机练习 14 mysql 命令 sql 语句实现步骤 shell 脚本导入 csv 格式文件到 mysql 数据库 secure-file-priv 特性 把文件拷贝到 mysql 指定目录下 上机练习 15 mysqldump 命令 上机练习 16 上机练习 14 运用上一节课学的 Shell 工具完成 1. 清洗数据《infotest.t…

黑马头条Day12-项目部署_持续集成

一、今日内容介绍 1. 什么是持续集成 持续集成&#xff08;Continuous integration&#xff0c;简称CI&#xff09;&#xff0c;指的是频繁地&#xff08;一天多次&#xff09;将代码集成到主干。 持续集成的组成要素&#xff1a; 一个自动构建过程&#xff0c;从检出代码、…

Markdown 语法大全详解

Markdown 语法大全详解 Markdown是一种轻量级标记语言&#xff0c;排版语法简洁&#xff0c;让人们更多地关注内容本身而非排版。它使用易读易写的纯文本格式编写文档&#xff0c;可与HTML混编&#xff0c;可导出 HTML、PDF 以及本身的 .md 格式的文件。因简洁、高效、易读、易…

langchain 入门指南 - 实现一个多模态 chatbot

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 在前面的文章中&#xff0c;我们学会了如何通过 langchain 实现本地文档库的 QA&#xff0c;又或者通过 langchain 来实现对话式的问答系…