java有两种定义多个实现的类型:interface和abstract class。抽象类和接口的区别是接口允许多继承,而抽象类只能单继承。
1. 接口的优势:
- 现有的类很容易别扩展,如果要加入新的方法只要实现一个接口就可以。
- 接口允许构造非层次结构。 ```java public interface Singer { AudioClip sing(Song s); }
public interface Songwriter { Song compose(int chartPosition); } public interface SingerSongwriter extends Singer, Songwriter { AudioClip strum();
void actSensitive();
}
3. 自从1.8以后,接口可以有默认实现方法。
<a name="3NG9w"></a>
### 2. 抽象骨架
抽象骨架就是将抽象类和接口相结合,接口定下需要实现的方法,抽象类实现部分的方法,并对这些方法进行组合,类似于设计模式的模板模式。通常将骨架实现类命名规则为Abstract+接口名,例`AbstractCollection`,`AbstractSet`,`AbstractList`和`AbstractMap`<br />编写一个骨架需定接口中哪些方法是基本的,其他方法可以根据它们来实现。 这些基本方法是你的骨架实现类中的抽象方法。 接下来,为所有可以直接在基本方法之上实现的方法提供接口中的默认方法,回想一下,你可能不会为诸如`Object`类中`equals`和`hashCode`等方法提供默认方法。 如果基本方法和默认方法涵盖了接口,那么就完成了,并且不需要骨架实现类。 否则,编写一个声明实现接口的类,并实现所有剩下的接口方法。 为了适合于该任务,此类可能包含任何的非公共属性和方法。
作为一个简单的例子,考虑一下`Map.Entry接口。 显而易见的基本方法是`getKey`,getValue`和(可选的)`setValue`。 接口指定了`equals`和`hashCode`的行为,并且在基本方面方面有一个`toString`的明显的实现。 由于不允许为Object类方法提供默认实现,因此所有实现均放置在骨架实现类中:
```java
// Skeletal implementation class
public abstract class AbstractMapEntry<K,V>
implements Map.Entry<K,V> {
// Entries in a modifiable map must override this method
@Override public V setValue(V value) {
throw new UnsupportedOperationException();
}
// Implements the general contract of Map.Entry.equals
@Override public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry) o;
return Objects.equals(e.getKey(), getKey())
&& Objects.equals(e.getValue(), getValue());
}
// Implements the general contract of Map.Entry.hashCode
@Override public int hashCode() {
return Objects.hashCode(getKey())
^ Objects.hashCode(getValue());
}
@Override public String toString() {
return getKey() + "=" + getValue();
}
}
由于骨架实现类是为了继承而设计的,所以你应该遵循条目 19中的所有设计和文档说明。为了简洁起见,前面的例子中省略了文档注释,但是好的文档在骨架实现中是绝对必要的,无论它是否包含 一个接口或一个单独的抽象类的默认方法。
总而言之,一个接口通常是定义允许多个实现的类型的最佳方式。 如果你导出一个重要的接口,应该强烈考虑提供一个骨架的实现类。 在可能的情况下,应该通过接口上的默认方法提供骨架实现,以便接口的所有实现者都可以使用它。 也就是说,对接口的限制通常要求骨架实现类采用抽象类的形式。