【第16条】接口优于抽象类

    Java语言提供了两种机制,可以用来定义一个允许多个实现的类型:接口抽象类。如果对它们的基本定义还不是很清楚请参考其它书籍。

 

    接口抽象类这二者比较起来,从特征来说,最明显的区别在于抽象类允许包含某些方法的实现,但是接口是不允许的。但是在使用方面还有一个更为突出的区别,就是抽象类是通过被子类继承来使用的;而接口是通过被实现来使用的。而Java是一种单继承机制的语言,所以就限制了抽象类的使用。(一个类只有一个超类或叫父类)当一个类已经继承了一个超类时,现在你再想因为一些原因让它再继承一个抽象类是不可能的(当然也有变通办法,就是先让这个抽象类继承那个超类,再把子类的超类改为这个抽象类。即原超类和子类的关系从父子关系变为了爷孙关系,中间插了这个抽象类)。这时候就能体现出接口的优势了——一个类可以实现多个接口(其实这也是Java之所以大胆地放弃多继承的原因)。

 

    再来罗列一下使用接口的其他好处吧:

1)已有的类可以很容易被更新,以实现新的接口。

     其实这就是上面说的,如果是使用抽象类就麻烦了。

 

2)接口是定义混合类型的理想选择。

 

3)接口使得我们可以构造出非层次结构的类型框架。

     层次结构用来描述组织机构这样的事物是非常合适的。但并不是所有事物都适用。

    

      举一个汽车的例子:

     【继承的思想】: 车 — 汽车 — 广义乘用车 — 轿车 — 小轿车 — 大众品牌小轿车 — 捷达车 — 捷达出租车

      这样的继承,直到“小轿车”之前还是合适的,从意义来说,这些类都应该是抽象类,因为无法实例化一个“小轿车”,它只是一类车的统称,只有某一辆,比如:京 B12345牌照号的(或者更严谨地用车架号)具体车才应该可以实例化。

      然而到了“大众品牌小轿车”之后就不合适了。显然,“大众品牌”不仅仅有“小轿车”,“捷达车”也不仅仅有“车租车”。这时候就该使用接口了。

 

public class MyCar extends 小轿车 implements 大众品牌, 捷达牌, 车租车able {

    public MyCar(String sn){
  .....
    }

}

 

4)接口使得安全地增强一个类的功能成为可能

     方法是使用包装类模式。我个人并不喜欢这样的做法,就不细说了。

 

   说了这么多接口的好处,那么抽象类是一无是处的吗?当然不是。一个明显的优势是,抽象类的演化(版本更新)比接口容易的多。如果在后续版本中你希望在抽象类中增加一个新方法,那么你直接增加就好了。你其实就是在抽象类中给出了一个默认的实现而已,子类会自然地继承这个方法,子类可以自由选择是否改写这个方法。

 

   接口就不行了。一旦发行你就不能在增加新的方法的定义了(还记得之前提到过几次的“你有义务保持向前兼容”吗?)。如果你增加了新的方法的定义,那么所有实现了此接口的类就统统要增加对此方法的实现,如果你的接口已经发布,那么这几乎是不可能的(除非只有你自己用你之前版本的发行包)。

 

   关于骨架实现类:在选择抽象类和接口时,并不是二选一的答案,或干脆枪毙掉抽象类。其实,你可以把接口和抽象类的优点结合起来,对于你希望导出(对外提供)的每一个重要接口都提供一个抽象类(骨架实现类)。接口的作用仍然是定义类型,骨架实现类负责所有与接口实现相关的工作。

 

   按照惯例,骨架实现类的命名方法为: AbstractInterface,这里的Interface指的是接口的名字。建议你也去读读AbstractList、AbstractMap的源码,或许有不少启发。(我也要去再读读...)

 

 

 

 

【Effective Java 学习笔记】系列连载专题请见:
http://tonylian.iteye.com/categories/64208

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值