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

作者:杨元

时间: 2024-10-12 05:31:25

Java中为什么有abstract interface 修饰类?的相关文章

java中可以让实例改变了类Feild(java这么干就是一个错误,你看到了就当做是类在该修改或这个类Feild)

class Person { public String name;//定义实例Feild public static int eyeNum;//定义类Feild } public class PersonTest { public static void main(String[] args) { System.out.println("Person的eyeNum的类Feild值是:" + Person.eyeNum); } } 运行: [[email protected] java

java中只能有一个实例的类的创建

Java中,如果我们创建一个类,想让这个类只有一个对象,那么我们可以 1:把该类的构造方法设计为private 2:在该类中定义一个static方法,在该方法中创建对象 package test; /* * 有时候我们希望一个类在任何时候都只有一个实例,这时候可以把该类设计为单例模式. * 要将一个类设计为单例模式,需要: * 1:把该类的构造方法的访问修饰符生命为private * 2:然后在该类中定义一个static方法,在该方法中创建类的对象 * * */ public class Sin

全面解释java中StringBuilder、StringBuffer、String类之间的关系

http://www.jb51.net/article/33398.htm String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间,StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象,StringBuffer和StringBuilder类功能基本相似 1. String 类  String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不

Java中如何使封装自己的类,建立并使用自己的类库?

转自:http://blog.csdn.net/luoweifu/article/details/7281494 随着自己的编程经历的积累会发现往往自己在一些项目中写的类在别的项目中也会有多次用到.你肯定会想:如何自己的写的一些常用的类积累起来,生成自己的类库?如果是这样的话,很庆幸,你遇到通道中人了,因为我也是这样做的.下面就介绍一下我是怎么做的吧 一.先来明白一下关于classpath和path的概念 path是java中用来进行编译和运行的程序所在的路径,而classpath是类所在的路径

关于JAVA中的Synchronization和interface误用

最近在写一个手机小应用系统的业务模块有一些对抽象和接口的规划主要是接口部分一般情况下同类或同性质的事物我们都会将其抽离实现接口统一以便业务实现节环更灵活地使用. 课题如下 在interface中声明 Synchronization 描述的方法是否可行要如何做 实际上Java 1.2以前的版本是允许这么做的 public interface DemoInterface{     synchronization void function1(); } 然而1.2以后的版本就不行了且这么做是是错误的.

Java中动态代理技术生成的类与原始类的区别 (转)

用动态代理的时候,对它新生成的类长什么样子感到好奇.有幸通过一些资料消除了心里的疑惑. 平时工作使用的Spring框架里面有一个AOP(面向切面)的机制,只知道它是把类重新生成了一遍,在切面上加上了后来定义的逻辑.这样就达到了动态的在原有类上增加一些功能.比如日志打印,拦截信息等. 这里只关心动态代理技术生成新的类,先不管虚拟机是如何去生成类,用了什么字节码生成技术,怎么产生字节码等这一系列动作.现在只关心最后生成的新类长什么样,它和老类有什么区别.为了获取到生成后的代理类的字节码并且反编译成我

Java中final与 static final 修饰的常量的区别

喵喵开车,新手上路,多多关照.有任何错误请在评论区指出. ...........................................我是万恶的分界线( ? ?ω?? )?......................................... final:用来修饰类,变量,方法: final修饰的类不能有子类,也不能被继承. final修饰的变量是一个常量,不能重新赋值. final修饰的方法不能重写 现在就说明final修饰的常量① 与 static final 修饰的常

Java基础知识(JAVA中String、StringBuffer、StringBuilder类的区别)

java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. 1.可变与不可变 String类中使用字符数组保存字符串,如下就是,因为有“final”修饰符,所以可以知道string对象是不可变的. private final char value[]; StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在Abstra

java中操作字符串都有哪些类?它们之间有什么区别?

Java 中,常用的对字符串操作的类有 String.StringBuffer.StringBuilder String : final 修饰,String 类的方法都是返回 new String.即对 String 对象的任何改变都不影响到原对象,对字符串的修改操作都会生成新的对象. StringBuffer : 对字符串的操作的方法都加了synchronized,保证线程安全. StringBuilder : 不保证线程安全,在方法体内需要进行字符串的修改操作,可以 new StringBu