我有不同意见,没有分也要说。
1. 一个子类如果implements一个接口,就必须实现接口中的所有方法(不管是否需要);如果是继承一个抽象类,只需要实现需要的方法即可,这是抽象类的一个优点非抽象类实现接口是才需要实现所有方法,抽象类是不需要的。
非抽象类继承抽象类必须实现抽象类中的抽象方法,而不是说只要实现需要的方法,所以这个也不是
什么优点。2. 如果一个接口中定义的方法名改变了,那么所有实现此接口的子类显然将无法通过编译,因为它们所实现的方法名已经不存在了,这是接口的一个缺点;而抽象类就不存在这个问题,只是为子类添加了一个新的方法(接口中旧的方法)
肯定是编译不过了,不过这个应该是一个优点,因为如果你经常需要改接口的化就是设计的失败!
抽象类如果修改了一个抽象方法的名称,子类同样编译不过,如果修改的是非抽象方法,编译没有问题,这个不确定性恰恰是抽象类的致命弱点。3. 看前面两点,似乎抽象类要比接口有着更多的优点,但它却有着一个难以弥补的缺点:就是一个子类只能有一个父类。A extends B . 这样A就拥有了B的所有方法和功能,但当A还想拥有C的功能的时候。就不能通过 A extends C 来实现,   而需要走一些弯路。目前系统架构的趋势就是由针对抽象(借口,抽象类)而不是具体编程,并且将功能尽可能的细分。   这就需要通过实现多个接口的方式来实现,显然,抽象类无法提供这样的功能。从系统重构的角度来说,一个具体类抽象出接口是十分方便的。只需要写一个接口,里面定义具体类的所有方法,然后在为这个具体类implement这个接口就可以了。而抽象类就要复杂的多,比如说 B extends A , C extends B 如果想要为c抽象出一个抽象类D的话,就需要找到它的最顶层A来从头做起,因为无法做到C extends Dinterface的绝对的抽象,看起来其实是抽象类的特例(所有方法都是抽象方法)。但是这并不说明interface没有抽象类有用,其实接口才是软件复用的关键,抽象类只是一个陪衬。
1.能使用interface绝对不考虑抽象类。
2.不要过多的使用抽象类,这样你的代码会很糟糕。
3.抽象类一般都是作为一个父类使用,提供一个默认实现(Collection中基本都是这样)。

解决方案 »

  1.   

    1. 一个子类如果implements一个接口,就必须实现接口中的所有方法(不管是否需要);如果是继承一个抽象类,只需要实现需要的方法即可,这是抽象类的一个优点非抽象类实现接口是才需要实现所有方法,抽象类是不需要的。
    非抽象类继承抽象类必须实现抽象类中的抽象方法,而不是说只要实现需要的方法,所以这个也不是
    什么优点。
    ---------------------------------------------------------------------------------------你误会了我的意思,继承抽象类的时候不需要实现全部方法,但此子类还是abstract的,无法实例化
      

  2.   

    抽象类如果修改了一个抽象方法的名称,子类同样编译不过,如果修改的是非抽象方法,编译没有问题,这个不确定性恰恰是抽象类的致命弱点。--------------------------------怎么会无法通过呢?初始名为aaa ,子类继承来了aaa的方法,当抽象类的aaa改为bbb后,子类就拥有了aaa,和bbb两个方法
      

  3.   

    肯定是interface比abstract好。
    一般情况下,如果能用interface就不用abstract。1. 一个子类如果implements一个接口,就必须实现接口中的所有方法(不管是否需要);如果是继承一个抽象类,只需要实现需要的方法即可,这是抽象类的一个优点其实interface的实现只要有相关的函数名称就可以了。即便没有任何实现都可以。这个不是问题。另外,interface 从设计上讲和abstract有很大不同。interface 表示实现类尊崇interface的“协议”,并不是由interface的特征。如果一个子类继承了abstract就决定了这个类的主要特征。所以设计上,interface不应该很“大”。还有一个具体的class可以实现无数的interface。所以interface设计要做到“接口隔离”。简单的也是说情愿有多个的interface也不要一个“全能的”interface。2. 如果一个接口中定义的方法名改变了,那么所有实现此接口的子类显然将无法通过编译,因为它们所实现的方法名已经不存在了,这是接口的一个缺点;而抽象类就不存在这个问题,只是为子类添加了一个新的方法(接口中旧的方法)“如果一个接口中定义的方法名改变了,那么所有实现此接口的子类显然将无法通过编译,因为它们所实现的方法名已经不存在了”。接口既然定义了就不能随便修改,“协议”是不能随便更改的。即便是abstract定义了一个方法也不能。你说得“能”,也就是abstract的固定的特性,不光是abstract,就是所有的子类也是有这个特性。这个也就是用abstract的唯一原因。第三点我不多说什么了。跟你说一个例子。
    六龄童和六小灵童都扮演“孙悟空(接口)”的角色,同时,我也能扮演“孙悟空(接口)”角色。我和六家族没有任何关系,只是我们三人都扮演了“孙悟空(接口)”。而六龄童和六小灵童是同一个家族的成员,这个家族可以是一个abstract,他们都有一个共同的“六”开头的名称。
      

  4.   

    interface还是abstract
    要看场合的不是谁好谁坏的问题。比如:模板方法模式
          要采用abstract
          而不能用interface分析好了   用什么都行  
      

  5.   

    连讲三句,就不让我再说了,这句话憋了我好久!interface的绝对的抽象,看起来其实是抽象类的特例(所有方法都是抽象方法)。但是这并不说明interface没有抽象类有用,其实接口才是软件复用的关键,抽象类只是一个陪衬。
    1.能使用interface绝对不考虑抽象类。
    2.不要过多的使用抽象类,这样你的代码会很糟糕。
    3.抽象类一般都是作为一个父类使用,提供一个默认实现(Collection中基本都是这样)。
    ---------------------------------------我的意思也是尽量使用interface,但抽象类也不是说没用,应该是各有各的优点。最好的方法就是写一个接口,然后做一个这个接口的default抽象类实现,根据需要选择实现接口还是继承抽象类,但这样的缺点就是写太多的类
      

  6.   

    随便说两句
    抽象类的优点:B继承A,C也继承A,假设类B、C中继承的fun1这个方法实现代码是一样的,则可以在A中写好代码,BC只要调用父类A的方法既可,不用重新编写代码;而其他BC方法名相同、具体实现不相同的代码,则在A写成抽象的方法。接口的优点:实现了类似于C++中多重继承的功能。
      

  7.   

    winterxu416(伟大的虫子) :抽象类的优点:B继承A,C也继承A,假设类B、C中继承的fun1这个方法实现代码是一样的,则可以在A中写好代码,BC只要调用父类A的方法既可,不用重新编写代码;而其他BC方法名相同、具体实现不相同的代码,则在A写成抽象的方法。
    ------------------------------------------------------------------------
    这句话讲的很好,以此类推,不断的extends出新的抽象类,不断完成新的方法,以供不同的类来继承实现,提高代码的复用性,但缺点是过于死板,针对性强了一些
      

  8.   

    showerXP(小阿!) :
    其实interface的实现只要有相关的函数名称就可以了。即便没有任何实现都可以。这个不是问题。另外,interface 从设计上讲和abstract有很大不同。interface 表示实现类尊崇interface的“协议”,并不是由interface的特征。如果一个子类继承了abstract就决定了这个类的主要特征。所以设计上,interface不应该很“大”。还有一个具体的class可以实现无数的interface。所以interface设计要做到“接口隔离”。简单的也是说情愿有多个的interface也不要一个“全能的”interface。-------------------------------------------------------要想实现接口隔离只能通过接口来实现,这也是abstract的最大缺陷
      

  9.   

    还是这些啊!贴一段让接口和抽象类结合的:interface I{
    void mA();
    }
    abstract class A{
    public abstract void mB();
    public void mA(){
    mB();
    }
    }
    class C extends A implements I{
    public void mB(){
    System.out.println("C.mB()");
    }
    }
    public class IA{
    public static void main(String[] args){
    I i = new C();//当然可以使用Class.forName("C")
    i.mA();
    }
    }其中I是公布给客户方的,而C是动态加载给客户方的,而A实现了动态加载给客户方时需要实现的代码。留下需要修改的代码给后来的代码去完成。至于I和A是否有关系都无所谓。反正这时候的客户端只要拿了个I去就行了。就像我们只要一个servlet一样。我才搞java不久,望高手指点。
      

  10.   

    初学者注意上面的代码是可以强制转型的。也就是说可以这样:((A)i).mB();
      

  11.   

    接口最大的优点应该是多重继承,假如一个类要继承多个类,只要implements多个接口即可。而多重继承是社会中普遍存在的现象,所以接口比抽象类有用的多,抽象类最多只能做接口的陪衬。
      

  12.   

    我认为讨论接口与抽象类的谁是谁非,我看大不必要了,既然存在必然有sun的考虑啦。大伙讨论讨论它们的使用环境更有意义吧。
      

  13.   

    回复人: javafaq2004(农村干部瞎忙活) ( ) 信誉:95 
    楼上的,如果“接口最大的优点应该是多重继承”,那内部类完全可以替代接口。还有,interface有一个特点是申明绝大部分都是public(我只在理论书上看过非public)。
      

  14.   

    showerXP(小阿!) 看来你得调试一下才行。你能申明为非public的吗?比如:interface{
      private void mA();
    }你认为行吗?
      

  15.   

    在abstract class的定义中,我们可以赋予方法的默认行为。但是在interface的定义中,方法却不能拥有默认行为,为了绕过这个限制,必须使用委托,但是这会 增加一些复杂性,有时会造成很大的麻烦。  
    在抽象类中不能定义默认行为还存在另一个比较严重的问题,那就是可能会造成维护上的麻烦。因为如果后来想修改类的界面(一般通过abstract class或者interface来表示)以适应新的情况(比如,添加新的方法或者给已用的方法中添加新的参数)时,就会非常的麻烦,可能要花费很多的时间(对于派生类很多的情况,尤为如此)。但是如果界面是通过abstract class来实现的,那么可能就只需要修改定义在abstract class中的默认行为就可以了。  同样,如果不能在抽象类中定义默认行为,就会导致同样的方法实现出现在该抽象类的每一个派生类中,违反了"one rule,one place"原则,造成代码重复,同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心。abstarct class在Java语言中体现了一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is a"关系,即父类和派生类在概念本质上应该是相同的。对于interface 来说则不然,并不要求interface的实现者和interface定义在概念本质上是一致的,仅仅是实现了interface定义的契约而已。abstract class和interface是Java语言中的两种定义抽象类的方式,它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理,因为它们表现了概念间的不同的关系(虽然都能够实现需求的功能)。这其实也是语言的一种的惯用法.
    所以我认为abstract class和interface不存在优劣之分,只存在使用者对其的理解、把握的差别.--以上思想源自duoshanx的文章《深入理解abstract class和interface》
      

  16.   

    突然想起这篇文章,贴出来大家参考一下。我的Java矢量绘图程序之路1. 下岗再就业。 2003年7月,我离开了工作6年的公司,开始新的生活。我已经开始喜欢,
    并用Java做了一些JSP/Servlet应用。此前我主要是在Delphi下工作,8年Delphi经验,枉为开发部经理。
    2. 想法。 一个朋友用Delphi开发了矢量控件,卖得不错,触动了我.我也想做一个,用业余时间,用什么? java,想都没想过Swing/awt是什么东西就开始准备。自以为基础还可以,因为
    做过Delphi矢量程序方面的经验,语言不同,方法相同。3. 选择。 
       1)JBuilder, Eclipse这两个东西,一个要付费的,一个是免费的。不过到了目前国人手里,基本都是免费的。用哪个?试了半天,都好。前者因为收到过Borland的律师信,所以不敢用,而且速度慢,配置要求高,而且没有Pure sun java,所以不用。 后者前身是IBM(没有记错的话)的东西,果然不错,但是还是没用。因为看了好久,也没觉得他们胜过UltraEdit多少。说到这,看官可能以为我蠢得可以,我也这样觉得。但最终选择了UltraEdit和Unix VI作为主要开发工具。   2) Java2D能做什么?我看了半天,可能JGraph这个开源项目是经典吧。我总结了一下JGrpah:设计非常好,扩展很容易,至少很多人这么说的。我也这么觉得。缺点是,很奇怪,速度很慢。程序宠大,自信靠一人之力,做不出来的,这是Team job.     Java2D太好了,很多功能,但是根据以前的经验,它往往有不足,不足在什么地方?就是没有完整的矢量应用。后来看到用Java2D做SVG和Flash的,才知道还不错,只是自己误解了。但是考虑到可能的产品移植,比如其它的语言环境,我还是放弃了大多数Java2D的功能。决定自己实现如Intersect,contains等等功能。即重写Rectangle2D,Line2D,Point2D等东西。可能蠢了点,看官不要笑话。
      3)没仔细看过Swing/Awt什么东西,也真的不太熟悉MVC,就做?可能吗。我不去想了,先设计设计吧,大年初一就设计了。先不管那么多。事实上我就这样过来了,而且还走得顺利。只是有很多地方要Refactoring罢了。这里,要感谢Google.
    4. 开动。***********************************************************
    ***********************************************************
    ***********************************************************  1)早看过了UML,也了解OO,以前还给同事上过OO的课呢,但是还是不了解OO. 在设计时,定义的不少 接口,都变成了AbstractClass,不知何故,只是因为在下面Implements一下之后,就一定要写东西,即使 没东西可写也要写一下,后来就换成了AbstractClass,烦。***********************************************************
    ***********************************************************
    ***********************************************************
     
      2)以前写矢量程序,是不得已,这次是自找苦吃,那么应该补一点课吧,买了好多几何书,没一本说全的,最后还是看看国外的MathForum,说得很好。记得有一篇文章是这样说的,看完这些东西,你又回到了高一水平。  3) 写成英文版吧,要换成中文也不难,但是换过去就麻烦了。所有的Comments/API documents都要写成英文,中文就回不去了。 英文水平实在不佳,但将就吧。  4) 实现所有的类库,实在是累,整整6个月的业余时间。中间还负责洗了两个月的碗,家庭支持最重要。当初选择UltraEdit是一时性起,但是调试过程实在是痛苦。不过现在感觉好多了。  
      
      5)从Point做起,Rectangle,Ellipse,Bezier Curve, Arc/chord/pie, 一直往前台写。怎么看都觉得不如  Point2D,Rectangle2D,Curve2D..但是后来运行正常,也觉得可以,因为不需要因为继承Java2D而承担过多的压力。 6)程序中,难免用上XML,我选择了JDOM, 在我的1.0.0版程序中, JDOM让我的JAR文件变成了1.5MB,我火大,自己写了一个MiniDOM,Jar文件缩小为380KB,开心.
      5.发布。  1)起个名吧,虽然前面Java定义了Package name,但觉得不好,我又改了,就定为JFDraw(现在可以在Google上查); 跟JDraw有点混,但不是一回事。  2)先发布个Free version再说,对于Java,写Shareware要担一点风险,所以还是先发布个Freeware吧。起名JFDraw Free Version 1.0.0.
      3)做了网页,到国内外网站上发布了一下,过了几天,有个England的朋友给我回信:
        ...  My first impression is that it's the best vector draw freeware
             program I've come across, and I'll no doubt be saying that on the
             details page      ...
        看上去还不错,有点夸大其辞,不过给了我信心。
      
      
     4)还有个朋友说,在Linux下运行良好,但事实上我没有在Linux下调试过(没空调试),很高兴。
     
     
     5)然后就是要求改进的信了,呵呵,心下想,这下可有事做了,有朋友支持就行。总算辛苦没有白费。
     
     
    6. 继续努力。  事情还远没有结束,这个程序才开了个头,不过,还是有很多想法,希望朋友们支持,以后多多努力以感谢大家。
    _______________________________________________________________所以符合自己或自己团队的就是最好的。
      

  17.   

    接口可多继承,地球人都知道,接口里的东东是public的。
    抽象类可以有部分实现,抽象类里的东东可以是protected、static etc。抽象类将某些东东标记为final可控制其实现。
    其他还有只可意会,不可言传:)
      

  18.   

    ntzls说话越来幽默了,是你自己说的,积极参与讨论。快把你的看家宝露出来。要不然,最多能说你参与了讨论,而不能算积极。(up也参与了讨论的。不好意思了。^_^)再来说一点前面没有提到的。接口的标记作用。比如:java.util.RandomAccess,java.io.Serializable等等。(对初学者补充:我们可以通过instanceof来判断这个对象是否是我们要处理的对象)。个人认为这对提高代码的可读性有很大的好处,需极力推广。看来以前理解接口是一种契约不是很好。接口就是接口,一个编码单元。另外接口的常量作用这里也没有提到。也补充一下吧!interface I{String str = "asdf";} takecare(大厅)还有在设计的时候,可以这么区分。
    如果是一个抽象实体,那么最好用抽象类;如果是操作的统称,那么就用接口。___________________________________________________________________________你是不是要表述这样一种意思?
    如果是设计带状态的实体就使用抽象类,如果只是方法的集合,就使用接口。
      

  19.   

    刚才关注takecare(大厅)搜索到的一贴,接口当指针使(详细可以参考Java与设计模式):import java.io.*;
    interface call
    {
    public void callme();
    }class inst implements call
    {
    public void callme()
    {
    System.out.println("Call inst");

    }


    }public class callback
    {
    static void  run(call cc)
    {
    cc.callme();
    }

    public static void  main(String[] args)
    {

    run(new inst());

    }

    }
    一个更为完整的实现。
    import java.io.*;
     interface call
    {
      
    public void proc(sender src,int wparam);
    }class sender
    {
    protected call ie;

    public sender(call event)
    {
    ie=event;
    }
    public void nofify(int wparam)
    {

    ie.proc(this,wparam);


    }




    }class receiver implements call
    {

    public void proc(sender src,int par)
    {
       
     System.out.println(src);
     System.out.println(par);

    }


    }
    class sandr extends sender
    implements call
    {        
    public sandr(call event)
    {
    super(event);

            
    }
        public void proc(sender src,int par)
    {
         
     System.out.println(src);
     System.out.println(par);

    }

    }
    public class callback
    {


    public static void  main(String[] args)
    {
       sandr s1=new sandr(null);
       sandr s2=new sandr(s1);
       s2.nofify(10);
       s1.proc(s2,10);
       s2.proc(s1,10);

    }

    }
    这在Java的事件模型中还是应用很广的。值得关注。
      

  20.   

    快睡觉了,再来一个吧!在接口中放置方法。interface I{
      static C c = new C();
      public class C{
        public void mA(){}
      }
    }
      

  21.   

    ----------------------------------------------------------------------
    回复人: javafaq2004(农村干部瞎忙活) ( ) 信誉:95  2004-10-21 03:53:00
    --------------------------------------------------------------^^^^^^^^走召弓虽!
    真是佩服javafaq2004的精力!
      

  22.   

    真精彩,其实大家对abstract或者interface来说,可能都了解的很透彻,不过,我觉得,在选择使用方面还是要考虑符合系统本身要求的,不是说什么都是最好的,符合才是最好的,就好比
    B继承A,C也继承A,假设类B、C中继承的fun1这个方法实现代码是一样的,则可以在A中写好代码,BC只要调用父类A的方法既可
    如果某一天,程序要改版,这样就改动大了,呵呵,要重载B,C里面的方法了不是,所以最重要的还是系统设计的时候,要尽可能考虑到以后的变化(比如程序的改版,完善...),来选择最适合的方法不过本人倒很喜欢interface,呵呵,单词好听
      

  23.   

    整理一下楼主的贴:1. 一个子类implements一个接口,如果该子类是非abstract类,就必须实现接口中的所有方法(不管是否需要);而如果该子类是abstract类,则可以实现接口的中方法也可以不实现。
       一个子类如果是继承一个抽象类,如果该子类是非abstract类,就必须实现基类中的所有抽象方法;而如果该子类是abstract类,则可以实现基类的中抽象方法也可以不实现。
       //这两种情况看起来是一样的,只不过,抽象类中可以有非抽象方法,而接口中必须全是抽象方法。2. 如果一个接口中定义的方法名改变了,那么所有实现此接口的子类显然将无法通过编译,因为接口的那个改名的方法在非抽象子类中没有实现。
       抽象类如果修改了一个抽象方法的名称,子类同样编译不过,但若修改的是非抽象方法,编译没有问题。
       //两者看起来看是差不多的,只不过修改的方法有抽象和非抽象之别。3. 关于
       抽象类如果修改了一个抽象方法的名称,子类同样编译不过,如果修改的是非抽象方法,编译没有问题,这个不确定性恰恰是抽象类的致命弱点。--------------------------------   怎么会无法通过呢?初始名为aaa ,子类继承来了aaa的方法,当抽象类的aaa改为bbb后,子类就拥有了aaa,和bbb两个方法   //初始名为aaa(应为抽象方法名),子类继承(并实现)了aaa的方法,当抽象类的aaa改为bbb后,子类就拥有了aaa,和bbb两个方法(子类这时只是拥有了一个新方法aaa,而抽象类的的抽象方法bbb在子类中没有实现,当然无法编译通过)
    //楼上有好多强人,学习......
      

  24.   

    takecare(大厅)走召弓虽!
    真是佩服javafaq2004的精力!_______________________________________________________________我白天要睡的。比如今天就是13:30起来的。^_^
      

  25.   

    我发现大家对接口的理解太过片面了,接口可以这样理解:它并不仅仅是一个类,它是一个规范~~~就象是一个系统,不断有旧的成员被新的成员取代,但系统仍然可以良好运转,为什么?就是因为所以的成员都遵守一个让系统正常运行的规范,在软件中,接口就扮演着这样一个角色,它并没有代替成员做具体的工作(coding)而是告诉成员该如何做(接口中的方法)再详细一些说就是接口中的方法只定义了参数类型,返回值类型,方法名字,就是告诉成员用什么样的工具(方法名)用什么资源(参数类型)完成什么样的工作(返回值类型)基于这样的出发点,几个毫不相干的抽象类甚至可以公用一个接口,即接口规范着抽象类这就是接口最主要的作用,通过接口耦合的系统有更好的整体性和可维护性,可扩展性
      

  26.   

    alaal(穷街)但是接口会在无形中至少增加一个类,如果再加上一个抽象隔离的话,就多出来两个。如果其他人也理解这种模式还凑合,如果其他人不理解呢?那就大幅度的增加了类结构图的复杂度(系统初期一般类的数量本来是不多的)。
      

  27.   

    的确,这种理论在开发和维护上是带来了很大的方便。但使用时呢?比如集合框架,IO包,难道我们在使用的时候不觉得类太多了设置有点乱的感觉?比如我选择了sun的IO包开始使用。一般来说,我不会详细去读文档,而且糟糕的是我可能水平还很差,这可符合大多数。但我发现了InputStream,因为这个名字很直观。那我就极有可能输入下面的代码:InputStream in = new InputStream();发现不行。那我再尝试一次,由于我想实行对象持久化,我再试试ObjectInputStream,我发现又不行。但我发现一个同样功能的包,可以这样执行。ObjectStream stream = new ObjectStream();
    stream.saveObject("C:/test", myObj);
    MyObj obj = (MyObj)stream.readObject("C:/test")'你认为Sun还会有可能比我选择?
      

  28.   

    一般来说,interface都会带一个abstract类。
    只不过这个类一般是protected的,所以看不到。至于增加了类那是必然的,不过不增加这些类,编码的工作可能更多,耦合的更紧。
    抽象层一般不会也不应该随意变更。至于接口更不应该随意变来变去。有一个好的系统分析不会出这种事情的说。接口和抽象类并不是取舍的关系,一般都是相互作用的关系。先定义一个接口,看需要增加一个抽象类比较好。反过来代码改动比较大。
      

  29.   

    AbstractClass和Interface的存在都是有道理的。。
    慢慢的等到抽象类和接口的使用都融成自己的一部分了,就不会再为该用接口还是用抽象类而争论了,用什么就是非常自然的一件事,根本不需要去解释什么理由。。