第23条:请不要在新代码中使用原生态类型

从java1.5发行版本开始,Java就提供了一种安全的替代方法,称作无限制的通配符类型,如果要使用范型,但是确定或者不关心实际的参数类型,就可以用一个问号代替。例如范型Set<?>的无限制通配符类型为Set<?>。这是最普通的参数化Set类型,可以持有任何集合。

关于Set<?>的两个事实: 
1、因为“?”标记可以代表任何类型,Set<?>可以持有任何类型的元素 
2、由于不知道“?”代表的类型,所有我们不能把任何元素放到Set<?>集合中

由于可以将任何元素放进使用原生态类型的集合中,因此很容易破坏该集合的类型约束条件;但不能将任何元素(除了null之外)放到Collection<?>中。

“不要在新代码中使用原生态类型”,这条规则有两个例外,这是因为“泛型信息在运行时就会被擦除”。

在获取类信息中必须使用原生态类型(数组类型和基本类型也算原生态类型),规范不允许使用参数化类型。换句话说:List.class,String[].class和int.class都是合法,但是List<String>.class和List<?>.class都是不合法的。

这条规则的第二个例外与instanceof操作符有关,由于泛型信息在运行时已被擦除,因此在参数化类型而不是无限制通配符类型(如List<?>)上使用instanceof操作符是非法的,用无限制通配符类型代替原生态类型,对instanceof操作的行为不产生任何影响。在这种情况下,尖括号<>和问号?就显得多余了。

下面是利用泛型来使用instanceof操作符的首先方法:

if(o instanceof set){Set<?> m = (Set<?>)o;// ...
}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

注意,一旦确定这个o是个Set,就必须将它转换成通配类型Set<?>,则不是转换成原生态类型Set,否则Set会引起编译时警告。

总之,使用原生态类型会在运行时导致异常,因此不要在新代码中使用。原生态类型只为了与引入泛型之前的遗留代码进行兼容和互用而提供的。另外Set<Object>是个参数化类型,表示可以包括任何对象类型的一个集合;Set<?>则是一个通配符类型,表示只能包含某种未知对象类型的一个集合;Set则是个原生态类型,它脱离了泛型系统。前两者是安全的,最后一种不安全。

术语介绍: 
原生态类型:List 
参数化的类型:List<String> 
泛型:List<E> 
有限制类型参数:List<E extends Number> 
形式类型参数:E 
无限制通配符类型:List<?> 
有限制通配符类型:List<? extends Number> 
递归类型限制:List <T extends Comparable> 
泛型方法: static<E> List<E> asList(E[] a)

第24条:消除非受检警告

用泛型编程时,会遇到许多编译器警告:非受检强制转换警告、非受检方法调用警告、非受检普通数组创建警告,以及非受检转换警告。

要尽可能地消除每一个非受检警告。如果消除了所有警告,就可以确保代码是类型安全的。

如果无法消除警告,同时可以证明引起警告的代码是类型安全的,只有在这种情况下才可以用一个@SuppressWarnings(“unchecked”)注解来禁止这条警告。

SuppressWarnings注解可以用在任何粒度的级别中,从单独的局部变量到整个类都可以。应该始终在尽可能小的范围中使用SuppressWarnings注解。它通常是个变量声明,或者是非常简短的方法或者构造器。永远不要在整个类上使用SuppressWarnings,这么做可能会掩盖了重要的警告。

总而言之,非受检警告很重要,不要忽略它们。每一条警告都表示可能在运行时抛出ClassCastException异常。要尽最大的努力消除这些警告。如果无法消掉同时确实是类型安全的,就可以在尽可能小的范围中,用@SuppressWarnings(“unchecked”)注解来禁止这条警告。要用注释把禁止该警告的原因记录下来。

第25条:列表优先于数组

1、数组是协变的(convariant),如果Sub是Super的子类型,那么数组类型Sub[]就是Super[]的子类型。 
泛型确实不可变的,List<Sub>不是List<Super>的子类型。

2、数组是具体化的(reified),因此数组在运行时才知道并检查它们的元素类型约束。 
泛型则是通过擦除(erasure)来实现,因此泛型只在编译时强化它们的类型信息,并在运行时丢弃(或者擦除)它们的元素类型约束。擦除就是使泛型可以与没有使用泛型的代码随意进行互用(见第23条)。 
下面代码片段是合法的:

Object[] objectArray = new Long[1];
objectArray[0] ="I don't fit in";//Throws ArrayStoreExecption
  • 1
  • 2
  • 1
  • 2

但是下面的代码则是不合法的:

List<Object> ol = new ArrayList<Long>();//Incompatible types 不兼容类型
ol.add("I don't fit in");
  • 1
  • 2
  • 1
  • 2

这其中无论是那种方法,都不能将String类型放进Long容器中,但是利用数组,你会在运行时抛出所犯的错误,利用List列表,则是在编译时就能看到发生的错误,我们当然希望在编译时发现错误了。

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

第26条:优先考虑泛型(需要重新读)

使用泛型比使用需要在客户端代码中进行转换的类型来的更加安全,也更加容易。在设计新类型的时候,要确保它们不需要这种转换就可以使用。这通常意味着要把类做成是泛型的。

第27条:优先考虑泛型方法(需要重新读)

泛型方法就想泛型对象一样,使用起来比要求客户端转换输入参数并返回值的方法来得更加安全,也更加容易。就像类型一样,你应该确保新方法可以不用转换就能使用,这通常意味着要将它们泛型化。

第28条:利用有限制通配符来提升API的灵活性(需要重新读)

为了获得最大限度的灵活性,要在表示生产者和消费者的输入参数上使用通配符类型。如果某个输入参数即是生产者,又是消费都,那么通配符类型对你就没有什么好处了,因为你需要严格的类型匹配,这是不用任何通配符而得到的。

下面的助记符便于让你记住要使用哪种通配符类型:

PECS 表示:producer-extends, consumer-super 
换句话说,如果参数化类型表示一个T生产者,就使用<? extends T>;如果它表示一个T消费者,就使用<? super T>。

PECS这个助记符突出了使用通配符的基本原则。Naftalin和Wadler称之为Get and Put Principle

第29条:优先考虑类型安全的异构容器(需要重新读)

集合API说明了泛型的一般用法,限制你每个容器只能有固定数目的类型参数。你可以通过将类型参数放在键上而不是容器上这一限制。对于这种类型安全的异构容器,可以用Class对象作为键。以这种方式使用的Class对象称作类型令牌。

《Effective Java中文版 第2版》PDF版下载: 
http://download.csdn.net/detail/xunzaosiyecao/9745699

作者:jiankunking 出处:http://blog.csdn.net/jiankunking

from: http://blog.csdn.net/jiankunking/article/details/54881166

Effective Java读书笔记七:泛型(部分章节需要重读)相关推荐

  1. Effective Java 读书笔记(七):通用程序设计

    Effective Java 读书笔记七通用程序设计 将局部变量的作用域最小化 for-each 循环优于传统的 for 循环 了解和使用类库 如果需要精确的答案请避免使用 float 和 doubl ...

  2. Effective Java读书笔记(二)

    Effective Java 读书笔记 (二) 创建和销毁对象 遇到多个构造器参数时要考虑使用构建器 创建和销毁对象 何时以及如何创建对象? 何时以及如何避免创建对象? 如何确保它们能够适时地销毁? ...

  3. Effective Java读书笔记完结啦

    Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...

  4. Effective Java 读书笔记(一)

    前言: 开个新的坑位,<effective java>的读书笔记,之后有时间会陆陆续续的更新,读这本书真的感触满多,item01和item02就已经在公司的项目代码中看到过了.今天这篇主要 ...

  5. Effective Java读书笔记三:创建和销毁对象

    第1条:考虑用静态工厂方法代替构造器 对于类而言,为了让客服端获得它的一个实例最常用的的一个方法就是提供一个公有的构造器.还有一种方法,类可以提供一个公有的静态工厂方法(static factory ...

  6. Effective Java读书笔记六:方法

    第38条:检查参数的有效性 绝大多数方法和构造器对于传递给它们的参数值都会有些限制.比如,索引值必须大于等于0,且不能超过其最大值,对象不能为null等.这样就可以在导致错误的源头将错误捕获,从而避免 ...

  7. Effective Java读书笔记五:异常

    第57条:只针对异常的情况才使用异常 异常是为了在异常情况下使用而设计的,不要将它们用于普通的控制流,也不要编写迫使它们这么做的API. 下面部分来自:异常 如果finally块中出现了异常没有捕获或 ...

  8. Effective Java读书笔记四:通用程序设计

    第45条:将局部变量的作用域最小化 在第一次使用变量时的地方声明: 几乎每个局部变量的声明都应该包含一个初始表达式: 如果在终止循环之后不需要循环变量的内容,for循环优于while循环.(for循环 ...

  9. Effective Java读书笔记二:枚举和注解

    第30条:用enum代替int常量 当需要一组固定常量的时候,应该使用enum代替int常量,除了对于手机登资源有限的设备应该酌情考虑enum的性能弱势之外. 第31条:用实例域代替序数 枚举的ord ...

最新文章

  1. 中山大学计算机学院运动会,喜讯!我院获2019中大校运会教工组团体第二名
  2. python数组转换为列表_python - 将一系列数组转换为单个列表 - SO中文参考 - www.soinside.com...
  3. fabric.js 不同类型 不同控件_耐温灌封胶都哪几个类型?不同类型的灌封胶有哪些不同之处?...
  4. 白话Elasticsearch35-深入聚合数据分析之案例实战更多metrics用法:统计每种颜色电视最大最小价格
  5. DL之BN-Inception:BN-Inception算法的简介(论文介绍)、架构详解、案例应用等配图集合之详细攻略
  6. iconpath 微信小程序_【报Bug】微信小程序 map 标记点iconPath图标 苹果手机 不能单个设置了。以前没有问题。现在不知道为啥不行了...
  7. #10010 「一本通 1.1 练习 6」糖果传递 (数学+贪心)
  8. 贴花纸怎么贴_陶瓷贴花纸DIY怎么做?
  9. 关于linux下制作静态库
  10. 怎么在activity里面操作listView的item里的组件的点击事件
  11. SAP License:SAP打油诗
  12. 安装deepin后会删除win10吗_不管是先装Win10还是先装Deepin,启动问题轻松搞定
  13. spring ,springmvc的常用标签注解
  14. pc上最好用的pdf阅读工具(PDF Xchange Viewer)
  15. Yocto动态软件包管理(Runtime Package Management)之:rpm和dnf
  16. LeetCode题解目录
  17. 【考试记录】Apsara Clouder基础技能认证:阿里巴巴编码规范(Java)
  18. 中南大学计算机基础在线作业答案三,中南大学计算机基础三答案.doc
  19. python魔方程序算法_python魔方程序算法_python算法(一)
  20. python贪吃蛇控制台_通过 PRA 的 python-pygame 玩转贪吃蛇

热门文章

  1. keepalived + haproxy 实现web 双主模型的高可用负载均衡--转
  2. 【数据库】关系型数据库优化操作
  3. TensorFlow教程之完整教程 2.7 字词的向量表示
  4. 真实而震撼:同班同学20年后,身价15亿与月薪5000元的区别
  5. 房价波动5%很正常 房地产市场绝不会崩盘
  6. 一文了解P2P的前世今生
  7. 如何设置mysql让其他人能访问_怎么配置MySQL数据库让别人远程访问
  8. jvm性能调优实战 - 35电商APP后台系统如何对Full GC进行深度优化
  9. MySQL-分库分表初探
  10. Java-CentoOS 7安装JDK8 (rpm格式 和 tar.gz格式) 多JDK设置默认的Java 版本