Effective Java笔记(32)谨慎并用泛型和可变参数

32、小心组合泛型和可变参数@ 在Java中,泛型和可变参数是两种非常强大的特性,但是它们在一起使用时需要小心。当你将泛型和可变参数结合在一起使用时,可能会导致编译器生成的警告或者运行时异常。这是因为Java中的可变参数实际上是一个数组,而泛型在编译时会进行类型擦除,这两者结合在一起可能会导致类型安全问题。在使用时,也可以进行类型检查来确保传递的参数类型正确。为了避免这种情况,可以将泛型和可变参数分开使用,或者在使用时进行类型检查。总之,当组合泛型和可变参数时,需要小心处理,避免可能导致类型安全问题的情况发生。方法中,我们创建了一个。 阅读详情

故事的小黄花 从出生那年就飘着

童年的荡秋千 随记忆一直晃到现在

        可变参数( vararg ) 方法(详见第 53 条)和泛型都是在 Java 5 中就有了,因此你可能会期待它们可以良好地相互作用;遗憾的是,它们不能 。 可变参数的作用在于让客户端能够将可变数量的参数传给方法,但这是个技术露底( leaky abstration ):当调用一个可变参数方法时,会创建一个数组用来存放可变参数;这个数组应该是一个实现细节,它是可见的 。因此,当可变参数有泛型或者参数化类型时,编译警告信息就会产生温乱 。

        回顾一下第28条,非具体化( non-reifable)类型是指其运行时代码信息比编译时少,并且显然所有的泛型和参数类型都是非具体化的。如果一个方法声明其可变参数为non-reifiable类型,编译器就会在声明中产生一条警告。如果方法是在类型为non-reifiable的可变参数.上调用,编译器也会在调用时发出一条警告信息。这个警告信息类似于:

         当一个参数化类型的变量指向一个不是该类型的对象时,会产生堆污染( heap pollution)。 它导致编辑器的自动生成转换失败,破坏了泛型系统的基本保证 。

        举个例子 。 下面的代码是对第 28 条中的代码片段稍加修改而得:

         这个方法没有可见的转换,但是在调用一个或者多个参数时会抛出 ClassCast­Exception 异常。 上述最后一行代码中有一个不可见的转换,这是由编译器生成的 。 这个转换失败证明类型安全已经受到了危及,因此将值保存在泛型可变参数数组参数 中是不安全的 。

        这个例子引出了 一个有趣的问题:为什么显式创建泛型数组是非法的,用泛型可变参数声明方法却是合法的呢?换句话说,为什么之前展示的方法只产生一条警告,而第 28 条中的代码片段却产生一个错误呢?答案在于,带有泛型可变参数或者参数化类型的方法在实践中用处很大,因此 Java 语言的设计者选择容忍这 一矛盾的存在 。 事实上,Java 类库导出了好几个这样的 方法,包括 Arrays.asList(T ... a )、Collections.addAll (Collection<? super T> C, T . . . elements ),以及 EnumSet.of (E first,E ... rest ) 。 与前面提到的危险方法不一样这些类库方法是类型安全的 。

        在 Java 7 之前,带泛型可变参数的方法的设计者,对于在调用处 出错的警告信息一点办法也没有。 这使得这些 API 使用起来非常不愉快 。 用户必须忍受这些警告,要么最好在每处调用点都通过@SuppressWarnings (飞rnchecked”)注解来消除警告(详见第 27条) 。 这么做过于烦琐,而且影响可读性,并且掩盖了反映实际问题的警告 。

        在 Java 7 中,增加了 SafeVarargs 注解,它让带泛型 vararg 参数的方法的设计者能够自动禁止客户端的警告 。 本质上,SafeVarargs 注解是通过方法的设计者做出承诺,声明这是类型安全的。 作为对于该承诺的交换,编译器同意不再向该方法的用户发出警告说这些调用可能不安全。

        重要的是,不要随意用@ SafeVarargs 对方法进行注解,除非它真正是安全的 。 那么它凭什么确保安全呢?回顾一下,泛型数组是在调用方法的时候创建的,用来保存可变参数 。 如果该方法没有在数组中保存任何值,也不允许对数组的引用转义(这可能导致不被信任的代码访问数组),那么它就是安全的 。 换句话说,如果可变参数数组只用来将数量可变的参数从调用程序传到方法(毕竟这才是可变参数的目的),那么该方法就是安全的 。

        值得注意的是,从来不在可变参数的数组中保存任何值,这可能破坏类型安全性 。以下面的泛型可变参数方法为例,它返回了一个包含其参数的数组 。 乍看之下,这似乎是一个方便的小工具 :

static<T> T[] toArray(T... args) {
    return args;
}

        这个方法只是返回其可变参数数组,看起来没什么危险,但它实际上很危险 !这个数组的类型,是由传到方法的参数的编译时类型来决定的,编译器没有足够的信息去做准确的决定 。 因为该方法返回其可变参数数组 ,它会将堆污染传到调用堆枝上 。

        下面举个具体的例子 。 这是一个泛型方法,它带有三个类型为 T 的参数,并返回 一个包含两个(随机选择的)参数的数组:

        这个方法本身并没有危险,也不会产生警告,除非它 调用了 带有泛型 可 变参数的toArray 方法 。 

        在编译这个方法时,编译器会产生代码, 创建一个可变参数数组,并将两个 T 实例传到 toArray 。 这些代码配置了 一个类型为 Object[ ]的数组,这是确保能够保存这些实例的最具体的类型,无论在调用时给 pickTwo 传递什么类型的对象都没问题 。toArray 方法只是将这个数组返回给 pickTwo ,反过来也将它返回 给其调用程序,因 此 pickTwo 始终都会返回一个类型为 Object[]的数组 。

        允许另一个方法访问一个泛型可变参数数组是不安全的 ,有两种情况例外 : 将数组传给另一个用@ SafeVarargs 正确注解过的可变参数方法是安全的,将数组传给只计算数组内容部分函数的非可变参数方法也是安全的 。

        确定何时应该使用 SafeVarargs 注解的规则很简单 : 对于每一个带有泛型可变参数或者参数化类型的方法,都要用@ SafeVarargs 进行注解,这样它的用户就不用承受那些无谓的、令人困惑的编译警报了 。 

        每当编译器警告你控制 的某个带泛型可变参数的方法可能形成堆污染,就应该检查该方法是否安全 。 这里先提个醒,泛型可变参数方法在下列条件下是安全的 :

  1. 它没有在可变参数数组中保存任何值 。
  2. 它没有对不被信任的代码开放该数组(或者其克隆程序) 。

        以上两个条件只要有任何一条被破坏,就要立即修正它 。

        注意,SafeVarargs 注解只能用在无法被覆盖的方法上,因为它不能确保每个可能的覆盖方法都是安全的 。 在 Java 8 中,该注解只在静态方法和 final实例方法中才是合法的;在 Java 9 中,它在私有的实例方法上也合法了 。

        总而言之,可变参数和泛型不能良好地合作,这是因为可变参数设施是构建在顶级数组之上的一个技术露底,泛型数组有不同的类型规则 。 虽然泛型可变参数不是类型安全的,但它们是合法的 。 如果选择编写带有泛型(或者参数化)可变参数的方法,首先要确保该方法是类型安全的,然后用@SafeVarargs 对它进行注解,这样使用起来就不会出现不愉快的情况了 。

【Milvus】实战指南:利用milvus-backup实现高效数据备份与恢复 本文详细介绍了如何利用官方工具milvus-backup为Milvus向量数据库实施高效的数据备份与恢复。文章从备份的必要性出发,逐步讲解了环境准备、配置要点、全量与按需备份操作,以及恢复数据的关键步骤和验证方法,旨在帮助用户构建可靠的数据安全防线,应对误操作或系统故障风险。 阅读详情

相关推荐

【文献阅读笔记】之基于注意力机制的深度学习路面裂缝检测

中文,计算机辅助设计与图形学学报,第 32 卷 第 8 期,2020 年 8 月。 DOI: 10.3724/SP.J.1089.2020.18059 摘要: 为实现自动准确地检测路面裂缝, 提升路面裂缝检测效果, 提出了一种基于注意力机制的裂缝检测网络 (attention-based crack networks, ACNet). 该网络采用编码器-解码器网络构架, 编码器采用 ResNet34 为骨干网, 提取路面裂缝特征; 在编码器和解码器间加入基于注意力机制的特征模块(attention-b

qq_44785998的博客 7593

第32项:谨慎地结合泛型和可变参数(Combine generics and varargs judiciously)

  可变参数方法(第53项)和泛型都在Java 5时添加到了平台中,所以你可能会期望它们会优雅地相互作用;可悲的是,它们不能相互作用。可变的目的是允许客户端将数量可变的参数传递给方法,但它是一个漏洞抽象( leaky abstraction):当你调用可变参数方法时,会创建一个数组来保存可变参数;该数组应该是一个实现细节,是可见的。因此,当可变参数具有泛型或者参数化类型时,会出现令人困惑的编译器警...

Coloured_Glaze的博客 2948

Linux之GTK系列教程

00、背上行囊1——程序员学习之道 01、背上行囊2——为什么要学习GTK 02、背上行囊3——GUI概述 03、背上行囊4——GTK简介 04、背上行囊5——GTK环境搭建( Linux ) 05、背上行囊6——GTK环境搭建( windows ) 06、踏上旅途1——一个简单的空白窗口 07、踏上旅途2——控件的添加 08、踏上旅途3——布局容器之水平布局 09、踏上旅途

每天积累一点点 2万+

effective java 第32条 谨慎并用泛型和可变参数

1.可变参数的作用在于让客户端能够将可变数量的参数传给方法,但这是个技术露底:当调用一个可变参数方法时,会创建一个对象数组Object[]用来存放可变参数;这个数组应该是一个实现细节,他是可见的。因此,当可变参数有泛型或者参数化类型时,编译警告信息就会产混乱。 2.当一个参数化类型的变量指向一个不是该类型的对象时,会产生堆污染(heap pullution)。它导致编辑器的自动生成转换失败,破坏...

u012864294的博客 473

别再为10G UDP发愁了!手把手教你用Xilinx 10G/25G Ethernet Subsystem IP核搭建FPGA网络栈(附12套工程源码)

本文详细介绍了基于Xilinx UltraScale架构的FPGA网络栈开发,重点讲解了10G/25G Ethernet Subsystem IP核的应用实践。通过手把手教程和12套工程源码,帮助开发者解决10G UDP通信中的物理层接口、协议栈实现和系统集成等核心挑战,实现高性能FPGA网络栈搭建。

weixin_42522575的博客 364

【C++ 使用libxlsxwriter库向excel表格中插入图片 CMake + VS2019】

使用libxlsxwriter向excel表格插入图片

恒星游历者的博客 755

带你快速看完9.8分神作《Effective Java》—— 泛型篇

文章目录26 不要使用原始类型(如List)27 消除非受检的警告28 列表优于数组29 优先考虑泛型30 优先考虑泛型方法31 利用限定通配符来提升API的灵活性PECS32 合理地结合泛型和可变参数33 优先考虑类型安全的异构容器 在泛型篇开始介绍之前,要先明确几个书中的术语,以免看得眼花缭乱: 术语 中文含义 举例 Parameterized type 参数化类型 List Actual type parameter 实际类型参数 String Generic type 泛型类

如切如磋,如琢如磨 1105

【精品5万字图文详解】特征平台建设方案与最佳实践

关键词:特征工程、特征平台、特征存储、特征服务、机器学习、数据工程摘要:本文全面介绍了特征平台的建设方案与最佳实践,从特征工程的基本概念出发,深入剖析了特征平台的核心组件、架构设计和实现方法。文章通过生动的类比和实例,使读者能够轻松理解特征工程的重要性及特征平台如何解决企业在机器学习过程中面临的数据管理挑战。同时,详细探讨了主流开源特征平台的对比分析、系统设计要点、实际落地案例以及未来发展趋势,为企业构建高效特征平台提供了全面的指导和参考。想象一下,小明是一位热爱烹饪的小学生。有一天,他想做一道美味的菜肴送

AI天才研究院 952

泛型方法和可变参数方法

1)泛型方法 他可以动态的设置返回的参数类型.方法名字要用 +空格+T 来修饰,参数中,必须带Class类型的参数.如果设置了Integer类型,则会返回Integer类型的值. public T getTemp(String temp, Class clazz) { T obj = null; obj = (T)getObject(); return obj; } 2)可...

报喜鸟 384

OpenCV实战之人脸美颜美型(八)——大眼(下)

我们需要将上述描述量化表达,以r代表上述变形区域的圆的半径,X表示原始图像像素到变形圆圆心的距离,Y表示像素变形后的其距离变形圆圆心的距离,则其形状大致如下图所示。如下图所示,我们可以规定处理区域为眼睛为圆心的一个圆形,从圆心区域开始图像会放大,但该放大的比例随着距离圆心的距离而变小,直至边缘区域的放大比例为0。不过在实际图像变形操作中我们要从目标图像映射到原图,因此我们需要将X/Y调换,让X表示变形后图像的像素距离变形圆中心的距离,Y表示原图像素距离变形圆中心的距离,则其形状如下图所示。

On my way 901

PHPStorm携手ThinkPHP8:开启高效开发之旅

本文围绕使用 PHPStorm 进行 ThinkPHP8 开发展开,先介绍开发环境搭建与 Xdebug 配置,再阐述 PHPStorm 集成 ThinkPHP8 的步骤,包括项目导入、解释器和服务器配置。还讲解了项目开发基础、数据库操作、高级技巧、调试处理及部署上线等内容,为开发者提供了从环境搭建到项目上线的完整指引,助力高效开展 ThinkPHP8 开发工作。

邓邓子的博客 1545

可变参数方法与泛型的那些事

The Java™ Tutorials — Generics :Non-Reifiable Types 不可具体化类型 https://blog.youkuaiyun.com/FIRE_TRAY/article/details/50640681?utm_source=itdadao&amp;amp;utm_medium=referral Non-Reifiable Types https://docs.orac...

每天进步一点点 735

Windows Server 2019 服务器一天之中内存利用率越来越高直到死机,疑似内存泄漏

环境: 华为桌面云虚拟机 Windows Server 2019 版本1809 OS内部版本17763.107 问题描述: Windows Server 2019服务器 一天之中内存利用率越来越高直到死机,不断扩容内存从10G到16G一重启就正常然后慢慢又循环,连续几天都这样,疑似内存泄漏 内存泄漏是什么? 内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪

本博客,博文仅代表个人操作经验,不能完全解决你的问题,仅供参考,佛系回复。 5394

《Effective Java》解读第32条:谨慎并用泛型和可变参数

摘要:泛型与可变参数的安全使用 Java中泛型与可变参数(varargs)的组合存在潜在风险。可变参数本质是数组,而泛型数组因类型擦除被禁止,这导致组合使用时可能引发堆污染。虽然编译器仅发出警告而非错误,是为了兼容标准库API(如Arrays.asList)。安全使用需注意:1)添加@SafeVarargs注解确保不修改数组或暴露给不可信代码;2)优先使用List替代可变参数。危险示例展示了间接调用时因类型擦除导致的运行时异常,而直接调用可正常工作。开发者应理解这种机制差异,谨慎处理泛型可变参数以避免类型安

Cosmoshhhyyy的博客 1139

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Effective Java 第三版 中文翻译

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

Coloured_Glaze的博客 3861

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

effective Java-泛型

泛型 26. 请不要使用原生态类型 泛型类和泛型接口统称为泛型generic 每一种泛型定义一组参数化的类型parameterized type 每一种泛型都定义一个原生态类型raw type:即不带任何实际类型参数的泛型名称,如List原生类型是List,主要为了泛型出现之前的代码进行兼容。 如果使用原生态类型,就失掉了泛型在安全性和描述性方面的所有优势 原生态类型List和参数化的类型List...

white_while的博客 425

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Effective Java 读书笔记

接口只应该用来定义类型,而不是用来导出常量标明实现了具有某种属性的接口 六、Lambda和表达式。

m0_49499183的博客 950

Effective Java 学习笔记之泛型

1.不要在新代码中使用原生态类型1) 声明中具有一个或者多个类型参数的类或者接口就是泛型类或接口 例如List<E>(读作‘E的列表’) 泛型类和接口统称作泛型2)每个泛型都定义一个原生态类型,即不带任何实际类型参数的泛型名称。例如List<E>相对应的原生态类型是List3)使用原生态类型,如果放入的类型不一致,在编译和运行时不会报错,直到从其中取出元素的时候才会收到提示 List

Heqianqian的博客 1112

Effective Java(第三版) 学习笔记 - 第五章 泛型 Rule26~Rule33

本文主要介绍泛型相关内容

weixin_44453385的博客 2207

【读书笔记】Effective Java(泛型)

读书笔记-Effective Java(泛型)

我的博客 230

《Effective Java》真的是一本值得一直去钻研的好书

文章目录《Effective Java》读书笔记第一章 引言第二章 创建和销毁对象1 考虑使用静态工厂方法替代构造方法**2 当构造方法参数过多时使用builder(建造者) 模式**3 使用私有构造方法或枚类实现Singleton 属性*4 使用私有构造方法执行非实例化*5 依赖注入优于硬连接资源(hardwiring resources)**6 避免创建不必要的对象*7 消除过期的对象引用*8 避免使用Finalizer 和Cleaner 机制**9 使用try-with-resources 语句替代t

追求幸福,探索未知的博客 8642

《Effective Java》泛型

[Java读书笔记] Effective Java(Third Edition) 第 5 章 泛型

朱嫑膘的博客 187

《Effective Java》知识点(4)--泛型

你也可以使用定制的键类型。>是安全的,而Set是不安全的。a. 数组是协变的,如果Sub是Super的子类型,那么Sub[]就是Super[]的子类型;b. 如果无法消除警告,同时可以证明引起警告的代码是类型安全的,才可以用一个@SuppressWarnings("unchecked")注解来禁止这条警告。32.3 如果选择编写带有泛型或者参数化可变参数的方法,首先要确保该方法是类型安全的,然后用@SafeVarargs对它进行注解。因此数组提供了运行时的类型安全,但没有编译时的类型安全,而泛型则相反。

myepicure的专栏 216

Effective Java 第二版 第5章 泛型、第6章 枚举和注解、第7章 方法

对于未被导出的方法(unexported method),作为包的创建者,你可以控制这个方法将在哪些情况下被调用。因此你可以,并且你也应该确保只将有效的参数值传递进来。因此,例外情况:在有些情况下,有效性检查非常expensive,或者根本是不切实际的,或者有效性检查已经隐含在计算过程中完成了。例如,Collections.sort(List), 列表中的所有对象都应该是可以相互比较的。排序过程中就会进行比较,提前检查列表中的元素是否可以相互比较是没有多少意义的。

kaikai_sk的博客 901

Effective java学习笔记

Effective java学习笔记使用静态方法代替构造方法 使用静态方法代替构造方法 //静态工厂方法举例 public static Boolean valueOf(boolean b) { return b ? Boolean.TRUE : Boolean.FALSE; } 优点: 1. 静态工厂方法有自己的名字,比起构造方法,使用时更易区分。 2. 不需要每次调用时都创建一个新对象,方法使用频繁的情况下,性能比使用构造方法更好 3.静态工厂方法可以返回其返回类型的任何子类型的对象。 4.静态工厂

qq_38022739的博客 1877

Effective Java解读

对书本每一章节解读、代码示例,更清晰的理解书本内容,明确说明优缺点

qq_48721706的博客 1027
上一篇: Effective Java笔记(31)利用有限制通配符来提升 API 的灵活性
下一篇: 2023软考系统架构设计师论文写作要点
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值