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. 通过对象的接口引用对象的更多相关文章

  1. Effective Java 第三版——6. 避免创建不必要的对象

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  2. Effective Java 第三版——14.考虑实现Comparable接口

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  3. Effective Java 第三版——21. 为后代设计接口

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  4. 《Effective Java 第三版》目录汇总

    经过反复不断的拖延和坚持,所有条目已经翻译完成,供大家分享学习.时间有限,个别地方翻译得比较仓促,希望有疑虑的地方指出批评改正. 第一章简介 忽略 第二章 创建和销毁对象 1. 考虑使用静态工厂方法替 ...

  5. 《Effective Java 第三版》新条目介绍

    版权声明:本文为博主原创文章,可以随意转载,不过请加上原文链接. https://blog.csdn.net/u014717036/article/details/80588806前言 从去年的3月份 ...

  6. effective Java 第三版学习笔记

    创建对象类型的 1,静态工厂方法代替构造器 静态工厂方法有名称,不容易混乱他的作用 不必再每次调用他的时候创建实例,创建实例的代价是高的,可以重复利用缓存的对象 静态工厂甚至能返回子类对象,例如在接口 ...

  7. Effective Java 第三版——1. 考虑使用静态工厂方法替代构造方法

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  8. Effective Java 第三版——3. 使用私有构造方法或枚类实现Singleton属性

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  9. Effective Java 第三版——7. 消除过期的对象引用

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

随机推荐

  1. Go版GTK:环境搭建(windows)

    Go版GTK:环境搭建(windows) https://blog.csdn.net/tennysonsky/article/details/79221507 所属专栏: Go语言开发实战     1 ...

  2. Snowflake Snow Snowflakes POJ - 3349(hash)

    You may have heard that no two snowflakes are alike. Your task is to write a program to determine wh ...

  3. oracle中to_timestamp和to_date什么区别

    date类型是Oracle常用的日期型变量,时间间隔是秒.两个日期型相减得到是两个时间的间隔,注意单位是“天”. timestamp是DATE类型的扩展,可以精确到小数秒(fractional_sec ...

  4. [PA2014]Bohater

    [PA2014]Bohater 题目大意: 有\(n(n\le10^5)\)只怪物,你的血量为\(z\).要打败第\(i\)只怪物时,你需要先消耗\(d_i\)点生命值,再恢复\(a_i\)点生命值. ...

  5. Victoria的舞会2——图的连通性及连通分量

    [Vijos1022]]Victoria的舞会2 Description Victoria是一位颇有成就的艺术家,他因油画作品<我爱北京天安门>闻名于世界.现在,他为了报答帮助他的同行们, ...

  6. Oracle内置函数

    单行函数:当查询表或试图时每行都能返回一个结果,可用于select,where,order by等子句中. 对于没有目标的select查询用dual表,这个表时真实存在的,每个用户都可以读取. 单行函 ...

  7. Java 适配器模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述适配器(Adapter)模式的: 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能 ...

  8. Redis、Memcache、MongoDb的优缺点

    Redis.Memcache.MongoDb的优缺点 Redis优点 支持多种数据结构,如 string(字符串). list(双向链表).dict(hash表).set(集合).zset(排序set ...

  9. consul 文档

    consul 服务发现 服务发现,用docker的时候可以使用,并且可以实现负载均衡. 因业务需要,所以留一下自己搜到比较好的资料吧 英文:https://www.consul.io/intro/ge ...

  10. html-webpack-plugin插件使用chunks属性时报错

    报错如下图: 原因是之前template属性使用的html模板内添加了script标签,将其删掉再使用chunks属性自动添加即可. (注释掉也不可以,必须删除!)