• Java中为什么有abstract interface 修饰类?


     如果有人问你为什么有abstract interface 修饰类,答案一定是他看到的这种方式一定是反编译出来的结果。实际中abstract interface和interface修饰的类没有区别。

    下面就上面的问题,介绍下抽象接口的概念。

    在程序设计过程中,读者很可能遇到这样一种困境:设计了一个接口,但实现这个接口的子类并不需要实现接口中的全部方法,也就是说,接口中的方法过多,对于某些子类是多余的,我们不得不浪费的写上一个空的实现。

           今天小菜提到的“抽象接口”,就是用来解决这个问题的。

           为了不误导读者,先说明一下,什么是“抽象接口”。

           所谓“抽象接口”,即在提供接口的同时,提供一个抽象类,用抽象类实现该接口(实际上这是缺省适配模式)。

           下面小菜举个例子,让读者体会这样做的好处。

           代码写的不咋地,为了防止读者看不懂,先上一张类图:

    具体代码:

      ITestInterface.java

    复制代码
    1 /*
    2     假设有一个顶层接口
    3 */
    4 public interface ITestInterface{
    5     void method1();
    6     int method2();
    7     boolean method3();
    8 }
    复制代码

      TestAbstract.java

    复制代码
     1 /*
     2     抽象类abstract实现了ITestInterface顶层接口
     3 */
     4 
     5 public abstract class TestAbstract implements ITestInterface{
     6     //找出接口中必要的方法,也就是子类必须实现的方法,定义成抽象方法,交由子类实现
     7     public abstract void method1();
     8     public abstract int method2();
     9     
    10     //一些独特的方法可以在抽象类中默认实现
    11     public boolean method3(){
    12         return true;
    13     }
    14 }
    复制代码

      

      TestClass1.java

    复制代码
     1 /*
     2     普通类TestClass1继承了TestAbstract抽象类
     3 */
     4 
     5 public class TestClass1 extends TestAbstract{
     6     
     7     //TestClass1必须实现抽象的method1方法,该方法最早是接口中定义的
     8     public void method1(){
     9         
    10     }
    11     //TestClass1必须实现抽象的method2方法,该方法最早是接口中定义的
    12     public int method2(){
    13         return 1;
    14     }
    15     
    16     //接口中的method3方法对于TestClass1无关紧要,因此不做重写。
    17 }
    复制代码

      TestClass2.java

    复制代码
     1 /*
     2     普通类TestClass2继承了TestAbstract抽象类
     3 */
     4 
     5 public class TestClass2 extends TestAbstract{
     6     
     7     //TestClass2必须实现抽象的method1方法,该方法最早是接口中定义的
     8     public void method1(){
     9     
    10     }
    11     //TestClass2必须实现抽象的method2方法,该方法最早是接口中定义的
    12     public int method2(){
    13         return 2;
    14     }
    15     
    16     //method3方法对于TestClass2来说至关重要,因此必须重写。
    17     public boolean method3(){
    18         return false;
    19     }
    20     
    21 }
    复制代码

    代码精讲:

        从以上例子可以看出,最高层的接口被一个抽象类实现,在抽象类中,我们把关键的method1、method2方法定义成抽象方法,强制子类去实现,而“独特”的method3方法在抽象类中做一个默认实现。

        等到TestClass1、TestClass2继承TestAbstract抽象类时,优势就体现出来了,TestClass1、TestClass2必须实现method1、method2,但如果用不到method3,可以直接无视。

        通过接口和抽象类的结合,避免了在实现接口的子类中出现大量的“无意义”实现,这个“无意义”实现,被缓冲到了抽象类中,完美展现了代码复用(可以把抽象类理解成接口和实现类之间的缓冲)。

        需要指出的是,我们既可以选择继承抽象类,也可以选择实现接口,并不是说一定要继承抽象类,看情况而定,这里是两种选择,两个机会。

          

                  写到这,或许读者觉得文章已经结束了,其实没有。。。

                  这样做的好处不仅仅是这一点,细细品味,假如我们向接口中增加了一个方法。。。

    具体代码:

      温馨提示:不要被代码吓到,其实这些代码和上边的差不多,只不过加了个方法而已。

      ITestInterface.java

    复制代码
     1 /*
     2     假设有一个顶层接口
     3 */
     4 public interface ITestInterface{
     5     void method1();
     6     int method2();
     7     boolean method3();
     8     //接口中新增加了方法
     9     String method4();
    10 }
    复制代码

      TestAbstract.java

    复制代码
     1 /*
     2     抽象类abstract实现了ITestInterface顶层接口
     3 */
     4 
     5 public abstract class TestAbstract implements ITestInterface{
     6     //找出接口中必要的方法,也就是子类必须实现的方法,定义成抽象方法,交由子类实现
     7     public abstract void method1();
     8     public abstract int method2();
     9     
    10     //一些独特的方法可以在抽象类中默认实现
    11     public boolean method3(){
    12         return true;
    13     }
    14     
    15     //抽象类中提供一个默认实现,这样就可以避免"惊动"所有子类
    16     public String method4(){
    17         return "";
    18     }
    19 }
    复制代码

      TestClass1.java

    复制代码
     1 /*
     2     普通类TestClass1继承了TestAbstract抽象类
     3 */
     4 
     5 public class TestClass1 extends TestAbstract{
     6     
     7     //TestClass1必须实现抽象的method1方法,该方法最早是接口中定义的
     8     public void method1(){
     9         
    10     }
    11     //TestClass1必须实现抽象的method2方法,该方法最早是接口中定义的
    12     public int method2(){
    13         return 1;
    14     }
    15     
    16     //接口中的method3方法对于TestClass1无关紧要,因此不做重写。
    17     
    18     //新增的方法对于TestClass1来说至关重要,因此必须重写
    19     public String method4(){
    20         return "Class1";
    21     }
    22 
    23 }
    复制代码

      TestClass2.java

    复制代码
     1 /*
     2     普通类TestClass2继承了TestAbstract抽象类
     3 */
     4 
     5 public class TestClass2 extends TestAbstract{
     6     
     7     //TestClass2必须实现抽象的method1方法,该方法最早是接口中定义的
     8     public void method1(){
     9     
    10     }
    11     //TestClass2必须实现抽象的method2方法,该方法最早是接口中定义的
    12     public int method2(){
    13         return 2;
    14     }
    15     
    16     //method3方法对于TestClass2来说至关重要,因此必须重写。
    17     public boolean method3(){
    18         return false;
    19     }
    20     
    21     //新增的方法对于TestClass2来说无关紧要,无需知道新增method4的存在
    22 }
    复制代码

    代码精讲:

        这段代码演示了假如项目已经成型,但是需求有变,我们不得不向接口中增加一个新的方法,假如子类直接实现了接口,那么这些子类都要修改,来实现接口新增的方法。

        但本例中的TestClass1、TestClass2子类没有直接实现接口,而是通过继承抽象类间接实现接口,这样好处一下就体现出来了!

        向接口中新增的方法,可以在实现接口的抽象类中缓冲一下,提供一个默认的实现,这样一来,就不必强制所有的子类(通过继承抽象类间接实现接口的类)都进行修改,可以形象的理解为“没有惊动子类”。而需要使用这个方法的子类,直接重写即可。

    小菜感慨:

        人类的智慧真伟大!数组和链表结合,产生了高效的哈希表;接口和抽象类结合,产生了优雅的缺省适配模式。大家努力吧!!!

    写在后面的话:

        世间没有完美的事物,设计模式也是如此,过多的讨论优缺点没有意义,合适的就是最好的,什么是合适的呢?这才是体现智慧的地方。

    转自:http://www.cnblogs.com/iyangyuan/archive/2013/03/11/2954808.html

    作者:杨元

    java多态的实现解释

    //定义超类superA  
    class superA  
    {  
    int i = 100;  
    void fun()  
    {  
    System.out.println(“This is superA”);  
    }  
    }  
    //定义superA的子类subB  
    class subB extends superA  
    {  
    int m = 1;  
    void fun()  
    {      
    System.out.println(“This is subB”);  
    }  
    }  
    //定义superA的子类subC  
    class subC extends superA  
    {  
    int n = 1;  
    void fun()  
    {      
    System.out.println(“This is subC”);  
    }  
    }  
    class Test  
    {  
    public static void main(String[] args)  
    {  
    superA a;  
    subB  b = new subB();  
    subC  c = new subC();  
    a=b;  
    a.fun();  (1)  
    a=c;  
    a.fun();  (2)  
    }  
    }
    
    /*
    运行结果为:
    
    This is subB
    
    This is subC
    
    上述代码中subB和subC是超类superA的子类,我们在类Test中声明了3个引用变量a, b, c,通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。也许有人会问:“为什么(1)和(2)不输出:This is superA”。java 的这种机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。
    
    所以,不要被上例中(1)和(2)所迷惑,虽然写成a.fun(),但是由于(1)中的a被b赋值,指向了子类subB的一个实例,因而(1)所调用的fun()实际上是子类subB的成员方法fun(),它覆盖了超类superA的成员方法fun();同样(2)调用的是子类subC的成员方法fun()。
    
    另外,如果子类继承的超类是一个抽象类,虽然抽象类不能通过new操作符实例化,但是可以创建抽象类的对象引用指向子类对象,以实现运行时多态性。具体的实现方法同上例。
    
    不过,抽象类的子类必须覆盖实现超类中的所有的抽象方法,否则子类必须被abstract修饰符修饰,当然也就不能被实例化了。
    */
    
    http://developer.51cto.com/art/200909/153887.htm
    View Code
  • 相关阅读:
    Jmeter Beanshell Assertion 成功或失败;这样beanshell的结果就可以在聚合报告的错误率中体现了;
    HDU-1233-还是畅通工程(最小生成树prim)
    HDU-1233-还是畅通工程(最小生成树kruscal)
    Hrbust 1794敌兵布阵(树状数组应用)
    Hrbust 2061消息队列(优先队列应用)
    Hrbust 1835 最长递增子序列(dp)
    "尚学堂杯"哈尔滨理工大学第七届程序设计竞赛——Hrbust2326 Blind Father
    "尚学堂杯"哈尔滨理工大学第七届程序设计竞赛——Hrbust2327 Collection Game
    "尚学堂杯"哈尔滨理工大学第七届程序设计竞赛——Hrbust2330 Final Ugly English
    HDU-1794 敌兵布阵(线段树单点更新求区间和)
  • 原文地址:https://www.cnblogs.com/hdu-2010/p/4151277.html
Copyright © 2020-2023  润新知