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

国庆节快乐~点击上方文字关注我们哦

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

接口作为引用

不推荐写法:

Vector subsribers = new Vector();

推荐写法:

List subsribers = new Vector();

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

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,如果程序依赖了这些额外的方法,这种类就一个只被用来引用它的实例)

—END—

扫描二维码

获取知识干货

后台技术汇

点个“在看”表示朕

已阅

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于Java中泛型类型的参数传入,我们需要先了解一下Java泛型的基本概念。 Java中的泛型是一种参数化类型的概念,即在定义类、接口或方法时,使用一个或多个类型参数来表示其中的某些类型,这些类型参数在使用时再被具体化。通过使用泛型,可以使代码更加通用、安全和可读性更强。 Java中的泛型类型参数可以用于类、接口和方法的定义中。在使用时,需要将具体的类型参数传递给它们,以指定其中的泛型类型。 下面以一个简单的例子来说明Java中参数传入泛型类型的用法。 ``` public class Box<T> { private T data; public Box(T data) { this.data = data; } public T getData() { return data; } public void setData(T data) { this.data = data; } } ``` 在这个例子中,我们定义了一个泛型类Box,其中的类型参数T可以在类的定义中被指定。在Box类的构造函数和getData、setData方法中,我们使用了泛型类型T来表示其中的某些类型。 现在我们可以创建一个Box对象,并将一个具体的类型参数传递给它,以指定其中的泛型类型。例如: ``` Box<Integer> box = new Box<Integer>(new Integer(10)); ``` 在这个例子中,我们创建了一个Box对象,并将Integer类型作为泛型类型参数传递给它。这样一来,我们就可以在Box对象中存储和获取Integer类型的数据了。 同样地,我们也可以创建其他类型的Box对象,例如: ``` Box<String> box = new Box<String>("Hello World!"); Box<Double> box = new Box<Double>(new Double(3.14)); ``` 通过这种方式,我们可以方便地定义、使用和重用泛型类型,从而使代码更加通用和灵活。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值