前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一文读懂《Effective Java》第52条:通过接口引用对象

一文读懂《Effective Java》第52条:通过接口引用对象

作者头像
后台技术汇
发布2022-05-28 12:46:21
2930
发布2022-05-28 12:46:21
举报
文章被收录于专栏:后台技术汇

一般来讲,应该优先使用接口而不是类来引用对象。如果有合适的接口类型,那么对于参数、返回值、变量和域来说,都应该使用接口类型来进行声明。如果你养成了使用接口作为类型的习惯,你的程序将会更加灵活。

接口作为引用

不推荐写法:

代码语言:javascript
复制
Vector subsribers = new Vector();

推荐写法:

代码语言:javascript
复制
List subsribers = new Vector();

List是Vector实现的接口,这里使用了List接口作为引用;这样当你决定更好实现时,比如说,我不需要Vector这种做了并发处理的工具类,想改用ArrayList,那么要做到的知识改变构造器中累的名称。

代码语言:javascript
复制
List subsribers = new ArrayList();

这样子,周围的所有代码的都可以继续工作,且不知道你已经将原来的实现类型变更了,对于这个变化是无感知的。

接口作引用的注意事项

上面提到,将实现修改而周围代码无感知。

有一点值得注意:如果原来的实现提高了某种特殊的功能,而这种功能并不是抽象接口所提供的通用约定,并且周围代码又依赖这个功能。那么,很关键的是,新的实现也必须提供相同的功能才可以保证,修改实现的代码运行如初。

以上面为例,我们将实现从Vector 改为 ArrayList,而恰好场景属于高并发的场景,周围业务也依赖于Vector 的同步策略,而ArrayList 是线程不安全的工具类,那么我们得出结论:使用ArrayList 替代Vector 是不正确的。

所以,我们在写代码时,如果业务依赖于实现类的任何特殊属性,最好能够在变量的地方给这个需求建立文档说明。

接口引用的实现类为什么要修改呢?

很简单,因为新的实现类提供了更好的性能,或者因为它提供了期望得到的额外功能。

举个例子:ThreadLocal 类,在它的内部,这个类在Thread 中石油了一个包级私有的Map 域,将每个线程的值(per-thread values)与ThreadLocal 实例关联起来。

在java 1.3 发行版中,这个域初始化为HashMap 实例。

在java 1.4 发行版中,这个域初始化为IdentityHashMap 实例。(IdentityHashMap是专用的Map实现,感兴趣的同学可以自行在jdk中查看源码)

如此一改,将会让ThreadLocal 机制变快许多。

接口作不适合作引用的3种情况

使用接口类型声明域“让程序员保持诚实”,因为凡是错误修改了实现类的地方,最终在编译阶段都会出错,从而减少后续运行时出现风险的代价。

但我们还是要清楚几个不适合使用接口作为引用的场景:

  • 如果没有合适的接口存在,完全可以用类而不是接口来引用对象。(比如,Random类,因为具体类没有关联的接口,别无他法了)
  • 对象属于一个框架,而框架基本类型就是类,不是接口。(对象属于基于类的框架,class-based framwork,就应该继续用相关的基类,往往是抽象类,来引用这个对象,而不是它的实现类)
  • 类实现了接口,但是它提供了接口不存在的额外方法。(例如:LinkedHashMap,如果程序依赖了这些额外的方法,这种类就一个只被用来引用它的实例)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-10-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 后台技术汇 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 接口作为引用
  • 接口作引用的注意事项
  • 接口引用的实现类为什么要修改呢?
  • 接口作不适合作引用的3种情况
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档