读《Effective java 中文版》(17)
2005-01-16 12:50
176 查看
读《Effective java 中文版》(17)
第16条:接口优于抽象类Java语言中的接口与抽象类的一些区别:
抽象类允许包含某些方法的实现,接口不允许。
为实现一个由抽象类定义的类型,它必须成为抽象类的一个子类。任何一个类,只要它定义了所有要求的方法,并且遵守通用约定,则它就允许实现一个接口。
java只允许单继承,抽象类作为类型定义受到了极大的限制。
看一下接口:
已有的类可以很容易被更新,以实现新的接口。只要:增加要求的方法,在类的声明上增加implements子句。
接口是定义mixin(混合类型)的理想选择。一个mixin是指这样的类型:一个类除了实现它的基本类型(primary type)之外,还可以实现这个mixin类型,以表明它提供了某些可选择的行为。接口之所以能定义mixin,因为它允许可选的功能可被混合到一个类型的基本类型中,而抽象类不能用于定义mixin类型,同样的理由是因为它们不能被更新到已有的类中:一个类不可能有一个以上的父类,并且在类层次结构中没有适当的地方来放置mixin。
接口使得我们可以构造出非层次结构的类型结构。看例子:
public interface Singer{
AudioClip sing(Song s);
}
public interface Songwriter{
Song compose(boolean hit);
}
为解决歌唱家本人也能做曲的情况,可以很简单地做到:
public interface SingerSongwriter extends Singer, Songwriter{
AudioClip strum();
void actSensitive();
}
如果用抽象类来做,会是如何?
接口使得安全地增强一类的功能成为可能,做法是使用第14条介绍的包装类模式。如果用抽象类型来做,则程序员除了使用继承没有别的方法。
接口不允许包含方法的实现。把接口和抽象类的优点结合起来,对于期望导出的每一个重要接口,都提供一个抽象的骨架实现(skeletal implementaion)类。接口的作用仍是定义类型,骨架实现类负责所有与接口实现相关的工作。按照惯例,骨架实现被称为AbstractInterface(注:此interface是所实现的接口的名字,如AbstractList,AbstractSet)。看一个静态工厂:
//List adapter for int array
static List intArrayAsList(final int[] a){
if (a==null) throw new NullPointerException();
return new AbstractList(){
public Object get(int i){
return new Integer(a[i]);
}
public int size(){
return a.length;
}
public Object set(int i,Object o){
int oldVal=a[i];
a[i]=((Integer)o).intValue();
return new Integer(oldVal);
}
}
}
这个例子是一个Adapter,它使得一个int数组可以被看作一个Integer实例列表(由于存在int和Integer之间的转换,其性能不会非常好)
骨架实现的优美之外在于,它们为抽象类提供了实现上的帮助,但又没有强加“抽象类被用做类型定义时候”所特有的严格限制。对一地一个接口的大多数实现来讲,扩展骨架实现类是一个很显然的选择,当然它也只是一个选择而已。
实现了这个接口的类可以把对于接口方法的调用,转发到一个内部私有类的实例上,而这个内部私有类扩展了骨架实现类。这项技术被称为模拟多重继承。
编写一个骨架实现类相对比较简单,首先要认真研究接口,并且确实哪些方法是最为基本的(primitive),其他的方法在实现的时候将以它们为基础,这些方法将是骨架实现类中的抽象方法;然后须为接口中的其它方法提供具体的实现。骨架实现类不是为了继承的目的而设计的。(怎么理解?)看例子:
//skeletal implementation
public abstract class AbstractMapEntry implements Map.Entry{
//primitives
public abstract Object getKey();
public abstract Object getValue();
//Entries in modifiable maps must override this method
public Object setValue(Object value){
throw new UnsupportedOperationException();
}
//Implements the general contract of Map.Entry.equals
public boolean equals(Object o){
if (o==this) return true;
if (!(o instanceof Map.Entry)) return false;
Map.Entry arg=(Map.Entry)o;
return eq(getKey(),arg.getKey())&&eq(getValue(),arg.getValue());
}
private static boolean eq(Object o1,Object o2){
return (o1==null?02==null:o1.equals(o2));
}
//implements the general contract of Map.Entry.hashCode
public int hashCode(){
return (getKey()==null?0:getKey.hashCode())^(getValue()==null?0:getValue().hashCode());
}
}
使用抽象类来定义允许多个实现的类型,比使用接口有一个明显的优势:抽象类的演化比接口的演化要容易的多。在后续的发行版中,如果希望在抽象类中增加一个方法,只增加一个默认的合理的实现即可,抽象类的所有实现都自动提供了这个新的方法。对于接口,这是行不通的。虽然可以在骨架实现类中增加一方法的实现来解决部分问题,但这不能解决不从骨架实现类继承的接口实现的问题。由此,设计公有的接口要非常谨慎,一旦一个接口被公开且被广泛实现,对它进行修改将是不可能的。
Posted by Hilton at February 16, 2004 08:57 PM | TrackBack
相关文章推荐
- Effective Java 3rd 条目17 最小化可变性
- 《Effective Java》(17~22)阅读笔记
- effective java(17) 之要么为继承而设计,并提供文档说明,要么就禁止继承
- Effective Java 中文版之学习 第1条:考虑用静态工厂方法代替构造器
- Effective Java 2.0_中文版_Item 4
- Android应用开发提高系列(3)——《Effective Java 中文版》读书笔记
- Android应用开发提高系列(3)——《Effective Java 中文版》读书笔记
- 《Effective java》笔记(第二版) --第四章(17-19)
- 深入Java虚拟机,Effective Java中文版
- 读《Effective java 中文版》(1)
- Effective Java 中文版
- Spring4.x官方参考文档中文版——第21章 Web MVC框架(17)
- 读《Effective java 中文版》(2)
- Effective Java 2.0_Item 1_中文版
- Android应用开发提高系列(3)——《Effective Java 中文版》读书笔记
- GradleUserGuide中文版 16)Ant插件 17)Logging 18)Daemon 19)Plugins
- 读《Effective java 中文版》
- 竹笋炒肉转载 -- 读《Effective java 中文版》(1)
- 读《Effective java 中文版》(3)
- 【Spring】Spring Framework Reference Documentation中文版17