} } }

    具体解析Java中抽象类和接口的差别

    添加时间:2013-7-25 点击量:

     在Java说话中, abstract class 和interface 是支撑抽象类定义的两种机制。恰是因为这两种机制的存在,才付与了Java强大的 面向对象才能。abstract class和interface之间在对于抽象类定义的支撑方面具有很大的类似性,甚至可以彼此调换,是以很多开辟者在进 行抽象类定义时对于abstract class和interface的选择显得斗劲随便。其实,两者之间还是有很大的区此外,对于它们的选择甚至反应出对 于题目范畴本质的懂得、对于设计意图的懂得是否正确、公道。本文将对它们之间的差别进行一番解析,试图给开辟者供给一个在二者之间进行选择的根据。
    懂得抽象类
      abstract class和interface在Java说话中都是用来进行抽象类(本文 中的抽象类并非从abstract class翻译而来,它默示的是一个抽象体,而abstract class为Java说话顶用于定义抽象类的一种办法, 请读者重视区分)定义的,那么什么是抽象类,应用抽象类能为我们带来什么益处呢?
      在 面向对象的概念中,我们知道所有的对象都是经由过程类来描画的,然则反过来却不是如许。并不是 所有的类都是用来描画对象的,若是一个类中没有包含足够的信息来描画一个具体的对象,如许的类就是抽象类。抽象类往往用来表征我们在对题目范畴进行解析、 设计中得出的抽象概念,是对一系列看上去不合,然则本质上雷同的具体概念的抽象。比如:若是我们进行一个图形编辑软件的开辟,就会发明题目范畴存在着圆、 三角形如许一些具体概念,它们是不合的,然则它们又都属于外形如许一个概念,外形这个概念在题目范畴是不存在的,它就是一个抽象概念。恰是因为抽象的概念 在题目范畴没有对应的具体概念,所以用以表征抽象概念的抽象类是不克不及够实例化的。
      在面向对象范畴,抽象类首要用来进行类型隐蔽。 我们可以机关出一个固定的一组行动的抽象描 述,然则这组行动却可以或许有随便率性个可能的具体实现体式格式。这个抽象描述就是抽象类,而这一组随便率性个可能的具体实现则发挥解析为所有可能的派生类。模块可以操纵一个 抽象体。因为模块依附于一个固定的抽象体,是以它可所以不容许批改的;同时,经由过程从这个抽象体派生,也可扩大此模块的行动功能。熟悉OCP的读者必然知 道,为了可以或许实现面向对象设计的一个核心的原则OCP(Open-Closed Principle),抽象类是此中的关键地点。
    从语法定义层面看abstract class 和 interface
      在语法层面,Java说话对于abstract class和interface给出了不合的定义体式格式,下面以定义一个名为Demo的抽象类为例来申明这种不合。
      应用abstract class的体式格式定义Demo抽象类的体式格式如下:

    abstract class Demo{
    
    abstract void method1();
    abstract void method2();


    应用interface的体式格式定义Demo抽象类的体式格式如下:
    interface Demo{
    
    void method1();
    void method2();

    }


    在abstract class体式格式中,Demo可以有本身的数据成员,也可以有非 abstract的成员办法,而在interface体式格式的实现中,Demo只可以或许有静态的不克不及被批改的数据成员(也就是必须是static final 的,不过在interface中一般不定义数据成员),所有的成员办法都是abstract的。从某种意义上说,interface是一种特别情势的 abstract class。
      从编程的角度来看,abstract class和interface都可以用来实现 design by contract 的思惟。然则在具体的应用上方还是有一些区此外。
      起首,abstract class 在 Java 说话中默示的是一种持续关系,一个类只能应用一次持续关系(因为Java不支撑多持续 -- 转注)。然则,一个类却可以实现多个interface。也许,这是Java说话的设计者在推敲Java对于多重持续的支撑方面的一种调和推敲吧。
      其次,在abstract class的定义中,我们可以付与办法的默认行动。然则在interface的定义中,办法却不克不及拥有默认行动,为了绕过这个限制,必须应用委托,然则这会增长一些错杂性,有时会造成很大的麻烦。
      在 抽象类中不克不及定义默认行动还存在另一个斗劲严重的题目,那就是可能会造成保护上的麻烦。因 为若是后来想批改类的界面(一般经由过程 abstract class 或者interface来默示)以适应新的景象(比如,添加新的办法或者给已用的办法中添 加新的参数)时,就会很是的麻烦,可能要花费很多的时候(对于派生类很多的景象,尤为如此)。然则若是界面是经由过程abstract class来实现的,那 么可能就只须要批改定义在abstract class中的默认行动就可以了。
      同样,若是不克不及在抽象类中定义默认行动,就会导致同样的办法实现呈如今该抽象类的每一个派生类中,违背了 one rule,one place 原则,造成代码反复,同样晦气于今后的保护。是以,在abstract class和interface间进行选择时要很是的警惕。
    从设计理念层面看 abstract class 和 interface
      上方首要从语法定义和编程的角度论说了abstract class和interface的区 别,这些层面的差别是斗劲低层次的、非本质的。本末节将从另一个层面:abstract class和interface所反应出的设计理念,来解析一下二者的差别。作者认为,从这个层面进行解析才干懂得二者概念的本质地点。
      前面已经提到过,abstract class在Java说话中表现了一种持续关系,要想使得 持续关系公道,父类和派生类之间必须存在is-a关系,即父类和派生类在概念本质上应当是雷同的。对于interface来说则不然,并不请求interface的实现者和interface定义在概念本质上是一致的, 仅仅是实现了interface定义的契约罢了。为了使论说便于懂得,下面将经由过程一个简单的实例进行申明。
      推敲如许一个例子,假设在我们的题目范畴中有一个关于Door的抽象概念,该Door具有履行两个动作open和close,此时我们可以经由过程abstract class或者interface来定义一个默示该抽象概念的类型,定义体式格式分别如下所示:
      应用abstract class体式格式定义Door:

    abstract class Door{
    
    abstract void open();
    abstract void close();
    }
    应用interface体式格式定义Door:
    interface Door{
    
    void open();
    void close();
    }

    其他具体的Door类型可以extends应用abstract class体式格式定义的Door或者implements应用interface体式格式定义的Door。看起来如同应用abstract class和interface没有大的差别。
      若是如今请求Door还要具有报警的功能。我们该如何设计针对该例子的类布局呢(在本例中, 主如果为了显现 abstract class 和interface 反应在设计理念上的差别,其他方面无关的题目都做了简化或者忽视)?下面将列举出可能的解 决规划,并从设计理念层面对这些不合的规划进行解析。
      解决计齐截:
      简单的在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 Principle),在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 Alarm Door extends Door implements Alarm{
    void open(){…}
    void close(){…}
    void alarm(){…}
    }

    这种实现体式格式根蒂根基上可以或许明白的反应出我们对于题目范畴的懂得,正确的揭示我们的设计意图。其 实abstract class默示的是is-a关系,interface默示的是like-a关系,大师在选择时可以作为一个根据,当然这是建树在对题目范畴的懂得上的,比如:若是我们认为AlarmDoor在概念本质上是报警器,同时又具有Door的功能,那么上述的定义体式格式就要反过来了。
    小结
      1.abstract class 在 Java 说话中默示的是一种持续关系,一个类只能应用一次持续关系。然则,一个类却可以实现多个interface。
      2.在abstract class 中可以有本身的数据成员,也可以有非abstarct的成员办法,而在interface中,只可以或许有静态的不克不及被批改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员办法都是abstract的。
      3.abstract class和interface所反应出的设计理念不合。其实abstract class默示的是is-a关系,interface默示的是like-a关系。
      4.实现抽象类和接口的类必须实现此中的所有办法。抽象类中可以有非抽象办法。接口中则不克不及有实现办法。
    5.接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不克不及从头定义,也不克不及改变其值。
      6.抽象类中的变量默认是 friendly 型,其值可以在子类中从头定义,也可以从头赋值。
      7.接口中的办法默认都是 public,abstract 类型的。
    结论
      abstract class 和 interface 是 Java说话中的两种定义抽象类的体式格式,它们之间有很大的类似性。然则对于它们的选择却又往往反应出对于题目范畴中的概 念本质的懂得、对于设计意图的反应是否正确、公道,因为它们发挥解析了概念间的不合的关系(固然都可以或许实现需求的功能)。这其实也是说话的一种的惯用法,读者伴侣可以或许细细领会。无论对感情还是对生活,“只要甜不要苦”都是任性而孩子气的,因为我们也不完美,我们也会伤害人。正因为我们都不完美,也因为生活从不是事事如意,所以对这些“瑕疵”的收纳才让我们对生活、对他人的爱变得日益真实而具体。—— 汪冰《世界再亏欠你,也要敢于拥抱幸福》

    分享到: