在java中的interface 和 abstract class 都是属于抽象层的概念,是对具体实例的行为的一种抽象,那么他们究竟有什么区别以及在什么时候使用interface,什么时候使用abstract class呢,下面将分别从几个方面来阐述:
1.从语法及编程的角度来看:
两者都是不能够被实例化的 ,因为他们描述的是抽象的概念,并没有对应的具体的实例,只有在对继承了该抽象类并实现了抽象方法的类或者对实现了某一接口的类进行实例化。
接口中的属性默认是public static final 类型的,抽象类则不是,接口中的方法默认是public的,抽象类中则可以申明非public的方法。接口中没有默认的行为,即不能有方法的实现,而抽象方法中可以有默认行为,即方法的实现。一个类可以实现多个接口,但只能继承一个抽象类。
2.从设计的角度来看:
什么时候该使用接口,什么时候使用抽象类呢?
抽象类与子类之间是is-a关系,即继承抽象类的类本质上是与该抽象类是同类型的,如,Animal与Dog,Animal可以作为抽象类,Dog可以作为派生类,Dog本质上还是Animal。
接口与子类之间是can do的关系,不同对象之间可以实现同一个接口。接口是对不同对象所执行的不同的行为提供一个封装,对外表现为一个统一的接口。抽象类是对同一类型的对象所具有不同的具体行为的抽象,同时也提供了这些同一类型的对象所具有的公共行为的实现。
当多个派生类具有共同的默认的行为时,可以使用抽象类,在抽象类中提供默认行为,子类自动继承。当要修改默认行为或者要增加新的方法时,使用抽象类,使用接口增加新的方法时,则所有实现该接口的类都要实现该方法,而某个实现类可能不需要该方法。
几个简单的例子。
假设有个Door的抽象概念,我们可以用abstract class 和 interface 来表示它,它有两个行为,分别为open,close,则有:
abstract class Door {
abstract void open();
abstract void close();
}
interface Door{
void open();
void close();
}
当我们要给Door增加一个报警功能时,一种实现方案是给Door增加alarm方法:
abstract class Door {
abstract void open();
abstract void close();
abstract void alarm();
}
interface Door{
void open();
void close();
void alarm();
}
那么具有报警功能的AlarmDoor的定义方式如下:
class AlarmDoor extends Door { void open() { … } void close() { … } void alarm() { … } }
或者
class AlarmDoor implements Door { void open() { … } void close() { … } void alarm() { … } }
这种方法违反了面向对象设计中的一个核心原则ISP(Interface Segregation Priciple),在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变(比如:修改alarm方法的参数)而改变,反之依然。
另一种解决方案是:
既然open、close和alarm属于两个不同的概念,根据ISP原则应该把它们分别定义在代表这两个概念的抽象类中。定义方式有:这两个概念都使用abstract class方式定义;两个概念都使用interface方式定义;一个概念使用abstract class方式定义,另一个概念使用interface方式定义。
显然,由于Java语言不支持多重继承,所以两个概念都使用abstract class方式定义是不可行的。后面两种方式都是可行的,但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、说明。
如果两个概念都使用interface方式来定义,那么就反映出两个问题:1、我们可能没有理解清楚问题领域,AlarmDoor在概念本质上到底是Door还是报警器?2、如果我们对于问题领域的理解没有问题,比如:我们通过对于问题领域的分析发现AlarmDoor在概念本质上和Door是一致的,那么我们在实现时就没有能够正确的揭示我们的设计意图,因为在这两个概念的定义上(均使用interface方式定义)反映不出上述含义。
如果我们对于问题领域的理解是:AlarmDoor在概念本质上是Door,同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢?前面已经说过,abstract class在Java语言中表示一种继承关系,而继承关系在本质上是"is a"关系。所以对于Door这个概念,我们应该使用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说明它又能够完成报警概念中定义的行为,所以报警概念可以通过interface方式定义。如下所示:
abstract class Door { abstract void open(); abstract void close(); } interface Alarm { void alarm(); } class AlarmDoor extends Door implements Alarm { void open() { … } void close() { … } void alarm() { … } }
参考:http://www.ibm.com/developerworks/cn/java/l-javainterface-abstract/