首页 > 代码库 > 关于Java抽象类和接口的区别与举例说明

关于Java抽象类和接口的区别与举例说明

声明:本文整理自 http://www.enet.com.cn/article/2007/1126/A20071126923475.shtml  中的文章

Java 中对于抽象类的定义有两种支持机制:

   抽象类(abstract class)和接口(interface).我们来看看这两种机制的不同在哪里?

零、在此处需要明确的指出以下几点:
  1.抽象类中抽象一词 限定的是不允许 有此类的分配实例到内存中
  2.抽象方法:在方法定义(声明)时在其前面有修饰符abastract
  3.普通方法:在方法定义(声明)时在其前面没有修饰符abastract
  4.若是一个方法或者变量不添加任何 访问权限修饰符 则为默认访问权限(default),此时同一个包里面的成员 可以对其进行访问
  5.Java 访问权限 从小到大 依次为 private < protected < defualt < public
下面从三个方面进行比较:
 
一、从语法定义层面看abstract class和interface
  下面以定义一个名为Demo的抽象类为例来说明这种不同。
  使用abstract class的方式定义Demo抽象类的方式如下:
  abstract class Demo{
    abstract void method1();
    abstract void method2();
    //some other abstract methods
    //--espc.
    //may has none-abstract methods in it
    void none-abstract-method1();
  }
  
  使用interface的方式定义Demo抽象类的方式如下:
  interface Demo{
    void method1();
    void method2();
  }
  
  说明:
  1.在一种方式中 可以含有 成员数据,抽象方法,普通方法. 并且类不对其组成部分的访问权限进行进行限制. 
    而在interface方式 中会对其 组成部分的访问权限进行限制.访问权限需要大于protected(即只能是为 default 或者 public)
    1)若是此接口含有成员数据,则一定是 static final 修饰的常量
    2)若是此接口含有成员方法,则一定是 abstract public 的方法(意味着 所有的成员方法都是abstract的)
    据此,从某种意义上来说,interface是一种特殊形式的abstract class.
  2.抽象类与抽象方法的关系是 :
    若是一个类有抽象方法则此类必定为抽象类,此时在类的定义前必须要有abastract修饰符
    反过来,对于抽象类不一定含有抽象方法.它可以只含有普通方法
二、从编程层面看abstract class和interface
  1.abstract class是一种继承关系(即为父与子的关系),一个类只能使用一次继承关系;但是,一个类却可以实现(implements)多个interface.
  2.在abstract class的定义中,我们可以赋予方法的默认行为。但是在interface的定义中,方法却不能拥有默认行为.
       而在抽象类中不能拥有默认行为 会给发布之后的日常代码维护造成困难.
    
三、从设计理念层面看abstract class和interface <本质区别>
  1.abstarct class体现了一种继承关系,父类和派生类在概念本质上应该是相同的.要想使得继承关系合理,父类和派生类之间必须是"is a"关系.
  2.对于interface 来说并不要求interface的实现者和interface定义在概念本质上是一致的.它要求的是仅仅是实现了interface定义的契约而已。
  
四、实例说明
  为了使论述便于理解,下面将通过一个简单的实例进行说明。 
  考虑这样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Door具有执行两个动作open和close.
  此时我们可以通过abstract class或interface来定义一个表示该抽象概念的类型.假如定义方式分别如下:
  
  使用abstract class方式定义Door:
  abstract class AbsDoor {
    abstract void open();
    abstract void close();
  }
  
  使用interface方式定义Door:
  interface IDoor {
    void open();
    void close();
  }
  
  其他具体的Door类型可以extends使用abstract class方式定义的AbsDoor或者implements使用interface方式定义的IDoor,
  此时,看起来好像使用abstract class和interface没有大的区别.
  若是后续有添加功能的需求,要求Door还要具有报警的功能.我们该如何设计针对该例子的类结构呢?
  下面将罗列出可能的解决方案,并从设计理念层面对这些不同的方案进行分析.
  1.解决方案一:
  简单的在AbsDoor的定义中增加一个alarm方法,如下:
  abstract class AbsDoor {
    abstract void open();
    abstract void close();
    abstract void alarm();
  }
  或者
  interface IDoor {
    void open();
    void close();
    void alarm();
  }
  
  那么具有报警功能的AlarmDoor的定义方式如下:
  class AlarmDoor extends AbsDoor {
    void open() { … }
    void close() { … }
    void alarm() { … }
  }
  或者
  class AlarmDoor implements IDoor {
    void open() { … }
    void close() { … }
    void alarm() { … }
  }
  这种方法违反了面向对象设计中的一个核心原则ISP(Interface Segregation Priciple).
  因为,在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起.
  这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变而改变,反之依然.
  
  2.解决方案二:
  既然open,close和alarm属于两个不同的概念,根据ISP原则应该把它们分别定义在代表这两个概念的抽象类中.
  定义方式有:
    A.两个概念都使用abstract class方式定义
    B.两个概念都使用interface方式定义
    C.一个概念使用abstract class方式定义,另一个概念使用interface方式定义
  然而,由于Java语言不支持多重继承.所以两A方式定义是不可行的.后面两种方式都是可行的.
  但是对于它们的选择却反映出我们对于问题领域中的概念本质的理解,对于设计意图的反映是否正确、合理。
  如果B方式来定义,那么就反映出两个问题:
    1、我们没有理解清楚问题领域:AlarmDoor在概念本质上到底是Door还是报警器?
    2、如果我们对于问题领域的理解没有问题,比如:我们通过对于问题领域的分析发现AlarmDoor在概念本质上和Door是一致的.
    那么我们在实现时就没有能够正确的揭示我们的设计意图,因为在这两个概念的定义上(使用B定义)反映不出上述含义。
  此时我们可以清楚的认识到:AlarmDoor在概念本质上是Door,同时它还有具有报警的功能.
  而在此之前已经说过,abstract class表示一种继承关系,而继承关系在本质上是"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() { … }
  }
结论:
  其实abstract class表示的是"is a"关系,interface表示的是"like a"关系,大家在选择时可以作为一个依据,当然这是建立在对问题领域的理解上的.
  比如:如果我们认为AlarmDoor在概念本质上是报警器,同时又具有Door的功能,那么上述的定义方式就要反过来了.
  abstract class和interface是Java语言中的两种定义抽象类的方式,它们之间有很大的相似性.
  由于因为它们表现了概念间的不同的关系,但是对于它们的选择却又往往反映出对于问题领域中的概念本质的理解.对于设计意图的反映是否正确合理.
 

关于Java抽象类和接口的区别与举例说明