Effective Java 第三版——64. 通过对象的接口引用对象
Tips
书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code
注意,书中的有些代码里方法是基于Java 9 API中的,所以JDK 最好下载 JDK 9以上的版本。

64. 通过接口引用对象
条目 51中指出,应该使用接口而不是类作为参数类型。更通常地说,应该更喜欢使用接口而不是类来引用对象。如果存在适当的接口类型,那么应该使用接口类型声明参数、返回值、变量和属性。真正需要引用对象的类的惟一时机是使用构造方法创建它的时候。为了具体说明这一点,考虑LinkedHashSet的情况,它是Set接口的一个实现。养成这样的习惯:
// Good - uses interface as type
Set<Son> sonSet = new LinkedHashSet<>();
不要是下面这个样子:
// Bad - uses class as type!
LinkedHashSet<Son> sonSet = new LinkedHashSet<>();
如果养成了使用接口作为类型的习惯,那么你的程序将更加灵活。如果决定要切换实现,只需在构造方法中更改类名(或使用不同的静态工厂)。例如,第一个声明可以改为:
Set<Son> sonSet = new HashSet<>();
所有的代码都会继续工作。周围的代码不知道旧的实现类型,所以它不会注意到这一变化。
有一点需要注意:如果原始实现提供了接口的常规约定不需要的某些特殊功能,并且代码依赖于该功能,那么新实现提供相同的功能至关重要。 例如,如果围绕第一个声明的代码依赖于LinkedHashSet的排序策略,那么在声明中用HashSet替换LinkedHashSet是不正确的,因为HashSet不保证迭代顺序。
那么,为什么要更改实现类型呢?因为第二个实现比原来的实现提供了更好的性能,或者因为它提供了原来的实现所缺乏的理想功能。例如,假设一个属性包含一个HashMap实例。将其更改为EnumMap将提供更好的性能和与键的自然顺序一致的迭代顺序,但是只能在键类型为枚举类型的情况下使用EnumMap。将HashMap更改为LinkedHashMap将提供可预测的迭代顺序,性能与HashMap相当,而不需要对键类型作出任何特殊要求。
你可能认为使用变量的实现类型声明变量是可以的,因为可以同时更改声明类型和实现类型,但是不能保证这种更改能否正常编译。如果客户端代码对原始实现类型使用了替换时不存在的方法,或者客户端代码将实例传递给需要原始实现类型的方法,那么在进行此更改之后,代码将不再编译。使用接口类型声明变量可以保持诚实可靠。
如果不存在适当的接口,则通过类而不是接口引用对象是完全合适的。 例如,考虑值类,例如String和BigInteger。 值类很少用多个实现类来编写。 它们通常是final的,很少有相应的接口。 将这样的值类用作参数,变量,属性或返回类型是完全合适的。
没有适当接口类型的第二种情况是属于框架的对象,其基本类型是类而不是接口。 如果一个对象属于这样一个基于类的框架,最好用相关的基类来引用它,它通常是抽象类,而不是它的实现类。 许多java.io包下的类(如OutputStream)都属于此类。
没有适当接口类型的最后一种情况是实现接口的类,但也提供了在接口中找不到的额外方法——例如,PriorityQueue具有Queue接口上不存在的comparator方法。 只有当程序依赖于额外的方法时,才应该使用这样的类来引用它的实例,这种情况应该是非常少见的。
这三种情况并不是面面俱到的,而仅仅是为了传达通过合适的类引用对象的情况。在实践中,给定对象是否具有适当的接口应该是显而易见的。如果是这样,使用接口引用对象,程序将更加灵活和流行。如果没有合适的接口,就使用类层次结构中提供所需功能的最小的具体类。
Effective Java 第三版——64. 通过对象的接口引用对象的更多相关文章
- Effective Java 第三版——6. 避免创建不必要的对象
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——14.考虑实现Comparable接口
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——21. 为后代设计接口
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- 《Effective Java 第三版》目录汇总
经过反复不断的拖延和坚持,所有条目已经翻译完成,供大家分享学习.时间有限,个别地方翻译得比较仓促,希望有疑虑的地方指出批评改正. 第一章简介 忽略 第二章 创建和销毁对象 1. 考虑使用静态工厂方法替 ...
- 《Effective Java 第三版》新条目介绍
版权声明:本文为博主原创文章,可以随意转载,不过请加上原文链接. https://blog.csdn.net/u014717036/article/details/80588806前言 从去年的3月份 ...
- effective Java 第三版学习笔记
创建对象类型的 1,静态工厂方法代替构造器 静态工厂方法有名称,不容易混乱他的作用 不必再每次调用他的时候创建实例,创建实例的代价是高的,可以重复利用缓存的对象 静态工厂甚至能返回子类对象,例如在接口 ...
- Effective Java 第三版——1. 考虑使用静态工厂方法替代构造方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——3. 使用私有构造方法或枚类实现Singleton属性
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——7. 消除过期的对象引用
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
随机推荐
- P=(1+1/(1-L))/2
1 y=1/x 2 y=1/(1-x) 3 4
- 使用SpringSecurity
前几天写了一个SpringBoot对拦截器的使用,在实际项目中,对一些情况需要做一些安全验证,比如在没有登录的情况下访问特定的页面应该解释的拦截处理.这一篇介绍使用SpringSecurity来做简单 ...
- 关于sql server的一种简单用法——在上面写查询语句,即可在下面修改数据
选择数据库中的表,右键单击-->编辑前200行,然后在显示的页面中选择带SQL标志的图标
- bootstrap-year-calendar全年日历插件
使用方法使用bootstrap-year-calendar插件需要引入jQuery.Bootstap3的相关依赖文件和插件本身需要的js和css文件. <link rel="style ...
- Centos服务器端口无法访问
使用GPRS A6 模块进行TCP连接的时候,一度认为A6模块坏掉了 最终只是服务器端口都被防火墙堵住了 使用之前一直用的 service iptables stop 找不到iptables 原来 ...
- HDU 5985 Lucky Coins 数学
Lucky Coins 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5985 Description Bob has collected a lot ...
- sql基本查询语句
查询语句的五中字句:where(条件查询),having(筛选),group by(分组),order by(排序),Limit(限制结果数) 一 单表查询 1.查询指定列:select 列名 fro ...
- django项目的新建相关的命令及配置
创建工程 django-admin startproject 工程名称 运行开发服务器 python manage.py runserver 创建子应用 python manage.py st ...
- Linux之通配符实验
作业五:通配符实验 反引号与()在此时都是表死获取结果 但是一般使用()的方式,因为反引号在多个反引号的时候无法正确指代 获取当前bash 的变量 echo $变量名 echo $? 表示上一次命令的 ...
- Sublime_SublimeServer
1. 遇到问题:如下代码第17行,获取本地json文件,如果直接在浏览器中打开引用该文件的.html文件,在chrme浏览器中并不能读取到json文件. var vm=new Vue({ el:&qu ...