首页 > 编程语言 >《Effective Java》阅读笔记-第五章

《Effective Java》阅读笔记-第五章

时间:2023-12-12 16:36:51浏览次数:36  
标签:Java Effective 编译 元素 List 类型 第五章 数组 泛型

Effective Java 阅读笔记

第五章 泛型

第 26 条 不要使用原生类型

随着泛型的普及,这条没什么可说的。

如果不知道具体类型,可以使用<?>来代替。

第 27 条 消除 unchecked 警告

原生类型到泛型转换时,编译会有警告,可以使用@SuppressWarnings("unchecked")来消除警告。并且应该在尽可能小的范围内使用 SuppressWarnings 注解

第 28 条 List 优于数组

数组是协变(Covariant),泛型是不变的(Invariant)。即子类数组可以赋值给父类数组,但是子类泛型不可赋值给父类泛型。

例子:

Object[] objectArray = new Long[1];
objectArray[0] = ""; // 抛出 java.lang.ArrayStoreException

这段代码是可以通过编译的,但是在运行时会抛出异常。

而下面这段代码直接编译不通过:java: 不兼容的类型: java.util.ArrayList<java.lang.Long>无法转换为java.util.List<java.lang.Object>
把运行时异常提前到了编译期,这无疑是非常好的:

// 编译报错
ArrayList<Object> list = new ArrayList<Long>();

泛型擦除:为了向前兼容,泛型检查只在编译期有效,运行时ArrayList<String>ArrayList是没有区别的。

同时,由于泛型擦除,使得泛型和数组不能同时使用,因此无法创建出泛型数组(比如List<String>[])。
而且其他类型转化为泛型时,在运行时并不能检查,(T) other这种类型转换其实就是转换成了Object。

第 29 条 优先考虑泛型

第 30 条 优先考虑泛型方法

实现一个类的时候,如果类或者方法比较通用,那就可以进行泛型实现,实现时可以使用通配符对泛型进行限定。

第 31 条 利用通配符提升灵活性

泛型是不变的,那就可以利用通配符来提升灵活性。

比如 Son 类继承 Father 类时,如果一个方法能处理 List<Father>,正常来说应该也可以处理子类,那方法的参数就可以使用List<? extends Father>,这样可以提升灵活性。更进一步,如果不是非要限定List类型,那么参数也可以使用Collection<? extends Father>或者是Iterable<? extends Father>这样的来提高灵活性。

但是不要使用通配符作为返回类型

通配符基本原则:producer-extends, consumer-super (PECS),并且所有comparable和comparator都是消费者。

简单来说就是

  • <? extends T> 用于声明泛型集合中的元素是"生产者",即从集合中读取元素。你可以从中读取元素,但不能往里面写入元素。用于方法参数时,表示方法中只会使用或读取泛型类型,而不会修改它。
  • <? super T> 用于声明泛型集合中的元素是"消费者",即可以向集合中写入元素。你可以往里面写入元素,但不能从中读取元素。用于方法参数时,表示方法中会修改泛型类型或向其中添加元素。

第 32 条 谨慎同时使用泛型和可变参数

可变参数底层就是一个数组,数组是协变的,不应和泛型一块使用。

但是也不是完全禁用,泛型可变参数方法需要使用@SaveVarargs注解进行注释,此时编译期不再警告。

更推荐需要可变参数的时候传入一个List<>,比如方法void aMethod(List<?>... lists)推荐写成void aMethod(List<List<?>> lists)

第 33 条 优先考虑类型安全的异构容器

异构容器(Heterogeneous Container)是指可以存储不同类型元素的数据结构或容器。与之相对的是同构容器(Homogeneous Container),同构容器只能存储相同类型的元素。

使用泛型容器的时候,可以考虑保存Class<?>对象来进行安全的类型转换。
但是由于泛型擦除原因,没有List<String>.class或者List<Integer>.class这样的类型,它们都是List.class

标签:Java,Effective,编译,元素,List,类型,第五章,数组,泛型
From: https://www.cnblogs.com/aliveneko/p/17897208.html

相关文章

  • 秦疆的Java课程笔记:65 面向对象 创建对象内存分析
    先写两个类//创建一个Pet类==============================packageOOP.demo;publicclassPet{publicStringname;publicintage;publicvoidshout(){System.out.println("喵~~");}}//主程序Application================......
  • java计算二个经纬度间的距离(百度坐标)
    1:背景工作中遇到计算二个地点之间的距离,根据百度经纬度进行计算。2:maven依赖<dependency><groupId>org.gavaghan</groupId><artifactId>geodesy</artifactId><version>1.1.3</version></dependency>3:代码实现packagecom.pacific.transfe......
  • 零基础30天学会Java-韩顺平
    第一章概述了解了该视频课程的大纲和Java的基本知识,Java1995年推出,目前稳定维护的有Java8和Java11版本。JVM(Java虚拟机):JVM包含于JDK中,Java虚拟机机制屏蔽了底层运行平台的差别,实现了“一次编译,到处运行"JRE(Java运行环境):JRE=JVM+Java的核心类库。JDK(Java开发工具包):JDK=JRE+Jav......
  • Java-04数组
    tip:[start]程序=逻辑+数据,数组是存储数据的强而有力的手段。——闫学灿tip:[end]一维数组数组的定义数组的定义方式和变量类似。java中数组的定义[]是写在数组名前面(与c++区分),开辟长度需要new,即面向对象。publicclassMain{publicstaticvoidmain(String[]......
  • java异常
    一、概述 二、JVM对异常的处理方案 三、异常处理1、try..catch 示例: 2、Throwable  3、throws  示例:  四、编译时异常和运行时异常区别示例:  五、自定义异常 六、throws和throw ......
  • java实现文件上传和下载
    本文实例为大家分享了java实现文件上传和下载的具体代码,供大家参考,具体内容如下文件的上传upload:文件上传客户端通过表单的文件域file 把客户端的文件上传保存到服务器的硬盘上页面首先对上传的表单有以下要求:必须有文件域:inputtype=file表单提交方式:method=post表......
  • java基本类型包装类
    一、概述  二、Integer包装类 三、int和String的转换 1、方式一 2、方式二 3、方式三 4、方式四 四、自动装箱和拆箱 五、日期格式化 示例: ......
  • 07 java运行时数据区域
    包含堆、方法区、程序计数器、本地方法栈、虚拟机栈。这就是运行数据区的几个部分。其中堆和方法区是线程共有的,其它数据区域是线程私有的。堆中存储对象数据。方法区中储存类信息、常量及静态变量等信息。方法栈中的栈帧和线程的寿命是一致的,储存方法执行时的相关常量,比如局部变量......
  • 高并发情况下的漏桶算法(javascript版)
    classLeakyBucket{//高并发情况下的漏桶算法 constructor(capacity,leakRate){//创建一个容量为capacity,每秒漏水量为leakRate的漏桶 this.capacity=capacity; this.leakRate=leakRate; this.water=0; this.lastLeakTime=Date.now(); ......
  • Java-SpringBean的生命周期
    Java-SpringBean的生命周期简单版实例化(Instantiation):当Spring容器启动时,它会检查配置文件或注解,然后实例化所有在配置中声明的Bean。这是通过构造函数或工厂方法进行的。属性设置(PopulationofProperties):容器实例化Bean后,会通过依赖注入或者setter方法将配置的......