Java 提供了两种机制,可以用来定义允许多个实现的类型:接口和抽象类。自从 Java 为继承引人了缺省方法(default method),这两种机制都允许为某些实例方法提供实现。主要的区别在于,为了实现由抽象类定义的类型,类必须成为抽象类的一个子类。因为 Java只允许单继承,所以用抽象类作为类型定义受到了限制。任何定义了所有必要的方法并遵守通用约定的类,都允许实现一个接口,无论这个类是处在类层次结构中的什么位置。
现有的类可以很容易被更新,以实现新的接口。如果这些方法尚不存在,你所需要做的就只是增加必要的方法,然后在类的声明中增加一个 implements 子句。例如,当Comparable、Iterable 和 Autocloseable 接口被引人 Java 平台时,更新了许多现有的类,以实现这些接口。一般来说,无法更新现有的类来扩展新的抽象类。如果你希望两个类扩展同一个抽象类,就必须把抽象类放到类型层次(type hierarchy)的高处,这样它就成了那两个类的一个祖先。遗憾的是,这样做会间接地伤害到类层次,迫使这个公共祖先的所有后代类都扩展这个新的抽象类,无论它对于这些后代类是否合适。
接口是定义 mixin(混合类型)的理想选择。不严格地讲,mixin 类型是指:类除了实现它的“基本类型”之外,还可以实现这个 mixin 类型,以表明它提供了某些可供选择的行为。例如,Comparable 是一个 mixin 接口,它允许类表明它的实例可以与其他的可相互比较的对象进行排序。这样的接口之所以被称为 mixin,是因为它允许任选的功能可被混合到类型的主要功能中。抽象类不能被用于定义 mixin,同样也是因为它们不能被更新到现有的类中:类不可能有一个以上的父类,类层次结构中也没有适当的地方来插入mixin。
接口允许构造非层次结构的类型框架。类型层次对于组织某些事物是非常合适的,但是其他事物并不能被整齐地组织成一个严格的层次结构。例如,假设我们有一个接口代表一个 singer(歌唱家),另一个接口代表一个 songwriter(作曲家):
public interface Singer {
AudioClip sing(Song s);
public interface Songwriter {
Song compose(int chartPosition);
}
}
在现实生活中,有些歌唱家本身也是作曲家。因为我们使用了接口而不是抽象类来定义这些类型,所以对于单个类而言,它同时实现 Singer和 Songwriter是完全允许的。实际上,我们可以定义第三个接口,它同时扩展 Singer 和Songwriter,并添加一些适合于这种组合的新方法:
public interface SingerSongwriter extends Singer, Songwriter i
{
AudioClip strumO;
void actSensitiveO;
}