Effective Java笔记(28)列表优于数组

《Effective Java》第28条:列表优于数组 (书上这里应该是翻译错了,因为最后总结的时候书上写的是不变的) 泛型不变是指:对于任意两个不同的类型 Type1和 Type2,List既不是List的子类型,也不是List的超类型,无论Type1 和 Type2 是什么关系。泛型只有在编译的时候强化它们的类型信息,在运行的时候就会擦除(丢弃)他们的元素类型信息,擦除类型后就相当于是原生态类型,可以与没有使用泛型的代码进行互用,主要是为了兼容性。协变是指如果类型Sub是类型Super的子类型,那么数组Sub[]也被认为是数组Super[]的子类型。 阅读详情

        数组与泛型相比,有两个重要的不同点 。 首先,数组是协变的( covariant ) 。 这个词听起来有点吓人,其实只是表示如果 Sub 为 Super 的子类型,那么数组类型 Sub[ ]就是Super[ ]的子类型。 相反,泛型则是可变的( invariant ):对于任意两个不同的类型 Type1 和 Type2,List<Type1>既不是 List < Type2 > 的子类型,也不是 List<Type2 >的超类型。 你可能认为,这意味着泛型是有缺陷的,但实际上可以说数组才是有缺陷的 。 下面的代码片段是合法的 :

Object[] objectArray = new Long[1] ;
objectArray[0] = "I don't fit in";

        但下面这段代码则不合法:

List<0bject> o1 = new ArrayList<Long>();
o1.add("I don't fit in");

        这其中无论哪一种方法,都不能将 String 放进 Long 容器中,但是利用数组,你会在运行时才发现所犯的错误;而利用列表,则可以在编译时就发现错误 。 我们当然希望在编译时就发现错误 。

        数组与泛型之间的第二大区别在于,数组是具体化的。因此数组会在运行时知道和强化它们的元素类型。如上所述,如果企图将 String 保存到 Long 数组中,就会得到一个 ArrayStoreException 异常 。 相比之下,泛型则是通过擦除( erasure)来实现的 。 这意味着,泛型只在编译时强化它们的类型信息,并在运行时丢弃(或者擦除)它们的元素类型信息 。 擦除就是使泛型可以与没有使用泛型的代码随意进行互用,以确保在 Java 5 中平滑过渡到泛型 。

        由于上述这些根本的区别 ,因此数组和泛型不能很好地棍合使用 。 例如,创建泛型、参数化类型或者类型参数的数组是非法的 3 这些数组创建表达式没有一个是合法的:new List<E > []、new List<String> []和 new E [] 。 这些在编译时都会导致一个泛型数纽创建( generic array creation )错误 。

        为什么创建泛型数组是非法的?因为它不是类型安全的 。 要是它合法,编译器在其他正确的程序中发生的转换就会在运行时失败,并出现一个 ClassCastException 异常 。这就违背了泛型系统提供的基本保证 。

        为了更具体地对此进行说明,以下面的代码片段为例 :

        我们假设第1行是合法的,它创建了一个泛型数组 。 第 2 行创建并初始化了一个包含单个元素的 List< Integer > 。 第 3 行将 List<String>数组保存到一个 Object 数组变量中,这是合法的,因为数组是协变的 。 第 4 行将 List< Integer>保存到 Object 数组里唯一的元素中,这是可以的,因为泛型是通过擦除实现的:List<Integer >实例的运行时类型只是 List, List<String>[ ] 实例的运行时类型则 是 List [],因此这种安排不会产生 ArrayStoreExceptio口异常 。 但现在我们有麻烦了 。 我们将一个 List<Integer>实例保存到了原本声明只包含 List<String>实例的数组 中 。 在第 5 行中,我们从这个数组里唯一的列表中获取了唯一的元素 。 编译器自动地将获取到 的元素转换成 String ,但它是一个 Integer ,因此,我们在运行时得到了一个 ClassCastException 异常。 为了防止出现这种情况,(创建泛型数组的)第1 行必须产生一条编译时错误 。

        从技术的角度来说,像 E 、List<E >和 List<String >这样的类型应称作不可具体化的( nonreifiable )类型。 直观地说,不可具体化的( non-reifiable )类型是指其运行时表示法包含的信息 比它的 编译时表示法包含的信息更少的类型 。 唯一可具体化的( reifiable )参数化类型是无限制的通配符类型,如 List <?>和 Map<?,?>  。虽然不常用,但是创建无限制通配类型的数组是合法的 。

        禁止创建泛型数组可能有点讨厌 。 例如,这表明泛型一般不可能返回它的元素类型数组 。 这也意味着在结合使用可变参数( varargs )方法和泛型时会出现令人费解的警告 。 这是由于每当调用可变参数方法时,就会创建一个数组来存放 varargs 参数 。 如果这个数组的元素类型不是可具体化的( reifialbe ),就会得到一条警告 。 利用 Saf eVarargs 注解可以解决这个问题 。

        当你得到泛型数组创建错误时,最好的解决办法通常是优先使用集合类型 List<E>,而不是数组类型 E[ ] 。 这样可能会损失一些性能或者简洁性,但是换回的却是更高的类型安全性和互用性。

        例如,假设要通过构造器编写一个带有集合的 Chooser 类和一个方法,并用该方法返回在集合中随机选择的一个元素 。 根据传给构造器的集合类型,可以用 chooser 充当游戏用的色子、魔术 8 球(一种卡片棋牌类游戏),或者一个蒙特卡罗模拟的数据源 。 下面是一个没有使用泛型的简单实现:

public class Chooser
{
    private final Object[] choiceArray;

    public Chooser(Collection choices) {
        choiceArray = choices.toArray();
    }

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

        要使用这个类,必须将 choose 方法的返回值,从 Object 转换成每次调用该方法时想要的类型,如果搞错类型,转换就会在运行时失败 。努力将Chooser 修改成泛型,修改部分如下所示:

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

    public Chooser(Collection<T> choices) {
        choiceArray = choices.toArray();
    }
    // choose method unchanged
}

        如果试着编译这个类,将会得到以下错误消息 :

        你可能会说 :这没什么大不了的,我可以把 Object 数组转换成 T 数组 : 

choiceArray = (T[]) choices.toArray() ;

        这样做的确消除了错误消息,但是现在得到了一条警告 :

        编译器告诉你,它无法在运行时检查转换的安全性,因为程序在运行时还不知道 T 是什么——记住,元素类型信息会在运行时从泛型中被擦除 。 这段程序可以运行吗?可以,但是编译器无法证明这一点 。 你可以亲自证明,只要将证据放在注释中,用一条注解禁止警告,但是最好能消除造成警告的根源 。

        要消除未受检的转换警告,必须选择用列表代替数组 。 下面是编译时没有出错或者警告的 Chooser 类版本 :

public class Chooser<T> {
    private final List<T> choiceList;
    public Chooser(Collection<T> choices) {
        choiceList = new ArrayList<> (choices);
    }
    public T choose() {
        Random rnd = ThreadLocalRandom.current();
        return choiceList.get(rnd.nextInt(choiceList.size());
    }
}

        这个版本的代码稍微冗长 一点,运行速度可能也会慢 一点, 但是在运行时不会得到ClassCastException 异常,为此也值了 。

        总而言之,数组和泛型有着截然不同的类型规则 。 数组是协变且可以具体化的;泛型是不可变的且可以被擦除的 。 因此,数组提供了运行时的类型安全,但是没有编译时的类型安全,反之,对于泛型也一样 。 一般来说,数组和泛型不能很好地混合使用 。 如果你发现自己将它们混合起来使用,并且得到了编译时错误或者警告,你的第一反应就应该是用列表代替数组 。

《Effective Java》第20条:接口优于抽象类 但是JDK源码中的 AbstractList 骨架实现类已经帮我们写好了很多的方法,只需要子类实现 get(int index) 和 size() 这两个最基本的方法(因为这两个方法没有通用实现,完全依赖具体列表的存储逻辑),基于 get 和 size,为 iterator、contains、indexOf、subList 等方法提供了默认实现(这些方法的逻辑是通用的),那么这个时候,我们只需要继承 AbstractList 骨架类,然后重写我们需要的方法即可。即使是使用组合方式,也不是一件容易的事情, 阅读详情

相关推荐

Effective Java读书笔记.pdf

Effective Java读书笔记.pdf

effective java 第三版 下载

我用夸克网盘分享了「Effective Java中文版(原书第3版).pdf」,点击链接即可保存。打开「夸克APP」在线查看,支持多种文档格式转换。链接:https://pan.quark.cn/s/ba1374210286。

qq_44679962的博客 1713

effective-java.pdf

effective-java.pdf

effective java(第三版) - pdf链接

第1条:考虑用静态方法而不是构造器 · Effective Java第三版中文版

m0_53353187的博客 8733

Effective Java第三版1

《Effective Java》第三版中文版目录 第一章 介绍 1 第二章 创建和销毁对象 4 1  考虑用静态工厂方法替换构造器 4 2  当遇到多个构造器参

Effective-java-3e-source-code:有效Java第三版的源代码,并进行了必要的补充以使其可运行

有效的Java,第三版 热点新闻! 最终在GitHub上提供了源代码。 快乐黑客!

《Effective Java》解读第28条:列表优于数组

在Java中,应当优先使用泛型集合(如List)而不是数组,以提高类型安全性、灵活性和代码的可维护性。

Cosmoshhhyyy的博客 326

《Effective Java》PDF资源下载 - Java开发者必备宝典

资源获取: 快来下载PDF,一起提升Java技能,让代码更简洁、更高效! 记得点赞、收藏、评论支持一波,更多优质资源持续更新中~

Effective Java笔记:接口优于抽象类

在 《Effective Java 第三版》中,作者 Joshua Bloch 对“接口优于抽象类”这一原则有着深入的探讨。在理解“接口优于抽象类”之前,我们需要明确二者的本质区别:书中的核心观点是:接口提供了更大的灵活性、更广泛的适用性以及更好的未来兼容性。因此,Joshua Bloch 在条目20中推荐开发者优先选择接口,原因如下:示例:接口的多重继承 相比抽象类,接口让一个类可以轻松拥有“多个行为”(复合式能力),而不需要受到单继承的限制。 书中例子常见的场景: 和 模式相比抽象类,接口更加关注对

eclipseC的博客 1021

(6)NUC980 SPI Nand 启动

方式一:下载到SPI-NAND-Flash中,这种方式可以将程序固化到SPIflash中,可以掉电保存。第二种方式下载到DDR中程序掉电丢失,但是DDR调试方便,时候调试的时候使用。之前的设置都是基于SD卡启动,今天测试一下是用SPI flash启动。方式二: 下载到DDR中,①设置为USB启动②下载到DDR中③运行。1:烧写BootLoader。

卤煮小鱼的博客 1754

汽水音乐自动化薅羊毛教程:从零搭建稳定赚钱脚本

📖 前言:为什么要学习自动化脚本?在数字时代,时间就是金钱。汽水音乐等App通过观看广告奖励用户金币的模式,本质上是将我们的时间转化为收益。本教程将教你如何用Python自动化这个过程,让程序为你"打工",实现被动收入。通过本教程,你将学到:移动端自动化测试的核心技术Python在自动化领域的实际应用如何将重复性任务转化为自动化流程创造属于自己的"数字员工"第一章:环境准备与基础配置1.1 硬件要求Android手机一部(建议使用备用机)USB数据线。

weixin_44947827的博客 5788

Java:Effective java学习笔记之 列表优先于数组

Java列表优先于数组1、列表优先于数组参考 1、列表优先于数组 参考 1、第二十五条:列表优先于数组 2、第25条:列表优先于数组

JMW1407的博客 412

手把手教你RK3588 NPU驱动与RKNN Toolkit,AI开发不迷路!

本文详细介绍了RK3588 NPU驱动安装与RKNNToolkit使用方法。首先阐述了RK3588芯片在嵌入式AI领域的优势,包括6TOPS算力和混合量化支持。随后分步骤讲解了NPU驱动安装流程,包括准备工作、编译安装、验证调试及常见问题解决。接着全面介绍了RKNNToolkit的环境搭建、基本使用流程和图像分类实战案例,涵盖模型转换、推理优化等关键环节。最后展望了RK3588在智能安防、工业自动化等领域的应用前景,为开发者提供了完整的嵌入式AI开发指南。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 433

学习记录:Effective Java -不要使用原生态类型,列表优于数组

消除非受检的警告可以提高代码的可读性和可维护性,同时避免潜在的运行时异常。在这个例子中,列表提供了更好的类型安全性和灵活性,因此通常情况下应该优先选择列表而不是数组。使用原生态类型可能导致编译时错误被延迟到运行时,因此应该尽量避免使用原生态类型。在Java中,列表(List)通常优于数组,因为列表具有更好的类型安全性和灵活性。通过使用泛型类型,编译器可以在编译时对类型进行检查,从而避免了潜在的运行时异常。避免使用原生态类型的方法是始终使用泛型类型。在Java中,原生态类型是指未经参数化的泛型类型,例如。

weixin_36639192的博客 713

VxWorks系列 快速导航

Vxworks系列快速阅览导航

Mr.Sugarcane 1308

华为od统一考试B卷【单词搜索】C++ 实现

找到它是一个小游戏,你需要在一个矩阵中找到给定的单词。假设给定单词 HELLOWORD,在矩阵中只要能找到 H->E->L->L->O->W->O->R->L->D连成的单词,就算通过。意区分英文字母大小写,并且您只能上下左右行走,不能走回头路。

MISAYAONE的博客 710

Effective Java---28列表优于数组

Effective Java一书中给出了列表优于数组的两个原因: 1、数组(Array)是协变的,而列表(List)支持泛型,是可变的。 2、数组是具体化的,在运行时会知道并强化它们的元素类型;泛型是通过擦除来实现的,只在编译的时候强化类型信息,在运行时擦除。 擦除就是使泛型可以与没有使用泛型的代码随意进行互用。 ...

weixin_44212383的博客 168

github创建账号第一步始终出错

github创建账号总结:第一次注册GitHub,填好用户名邮箱密码后进入下一步就卡在哪里,上面还提示Unable to verify your captcha response等,进入网址的解决办法以及下载其他的浏览器也无法解决,用手机浏览器抱着试一试的心态竟然成功了,分享给大家。手机下载谷歌浏览器,进入GitHub正常注册,能向下继续,邮箱验证完以后再用电脑登陆就ok啦

计算机毕业论文源码,学生个人网页制作html源码。贴近用户做网络推广和互联网优化。 4376

Effective java 列表优先于数组

看到这个标题的时候,我有个疑惑:是不是优先使用列表,能用列表就尽量用列表吗?我觉得,之所以说列表优于数组,应该是在某些语法设计方面,列表有比较大的优势。但是要具体问题具体分析,数组也有自身的优势(对于固定长度的序列,性能更加高),而且在某些情况下,列表的所谓的优势并不能发挥。 数组是协变且可以具体化的;泛型是不可变的且可以被擦除的(不可具体化的)。 ** 协变与不可变类型 数组是协变类型,指继承关系的。 泛型是不可变类型(也就是final类型),没有继承关系。无限制通配符类型是一个特例。 //这段

菜园子丶For丨丶Tomorrow的博客 215

qq对接openclaw,通过qq发送命令

把 OpenClaw 接入 QQ 和微信,目前主流的微信文章和教程主要提供了两种截然不同的路径。我为你梳理了它们的核心区别和关键步骤,你可以根据自己的需求来选择。

suny8的专栏 270

6、核函数与再生核希尔伯特空间:原理、应用与实践

本文系统介绍了核函数与再生核希尔伯特空间(RKHS)的理论基础、核心性质及其在机器学习和信号处理中的广泛应用。文章从核方法的优势出发,阐述了其在非线性建模、正则化和算法核化方面的独特价值,并深入探讨了正定核、Mercer定理、表示定理等关键理论。通过构建多种标准核与工程专用核,展示了核函数的设计灵活性。结合支持向量回归(SVR)模型与多个MATLAB示例,详细说明了核方法的实际应用流程与操作技巧。最后,总结了核方法的应用领域、未来发展方向及学习实践建议,为读者提供了一套完整的理论与实践指南。

z2a3b4c5d的博客 144

Effective Java 第三版 中文翻译

effective-java-third-edition 介绍 Effective Java 第三版全文翻译,纯属个人业余翻译,不合理的地方,望指正,感激不尽! 目录 推荐序 前言 致谢 第一章 引言 第二章 创建和销毁对象   本章涉及创建和销毁对象,包括何时以及如何创建它们,何时以及如何避免创建它们,如何确保它们被及时销毁,以及如何管理在销毁之前必须进行的清理操作。 第1项:考虑静态工...

Coloured_Glaze的博客 3861

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Effective Java读书笔记

第一章 引言 本文用来记录Effective Java学习过程中的各个知识点,受此时能力所限,有些点可能讲的不太清楚,或者理解有错误的地方,请多多指教! 第二章 创建和销毁对象 第一条 用静态工厂方法代替构造器 可参考文章:https://blog.youkuaiyun.com/u014129886/article/details/89670049 总而言之,静态工厂方法和共有构造器各有各的用处,我们需要理解他们各自的长处,静态工厂经常更加合适。 此处的静态工厂方法与设计模式中的工厂模式不同,这里是一种构造

逆水行舟,不进则退 1441

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Effective Java 读书笔记

读书笔记

white_while的博客 1648

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

effective java 第25条 列表优先于数组

第25条 列表优先于数组 /** * 25条,列表优先于数组 * sub为super的子类型,则sub[]就是super[]的子类型. * 而 list<sub>则不会是list<super>的子类型. * 这种不是说泛型是有缺陷的,而是说数组是有缺陷的. * */ public void fanxing25() { //下面这种写法是合法的...

y41992910的博客 240
上一篇: Effective Java笔记(27)消除非受检的警告
下一篇: Effective Java笔记(29)优先考虑泛型
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值