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
Java中为什么有abstract interface 修饰类?的更多相关文章
- 接口中字段的修饰符:public static final(默认不写) 接口中方法的修饰符:public abstract(默认不写)abstract只能修饰类和方法 不能修饰字段
abstract只能修饰类和方法 不能修饰字段
- java中只能有一个实例的类的创建
Java中,如果我们创建一个类,想让这个类只有一个对象,那么我们可以 1:把该类的构造方法设计为private 2:在该类中定义一个static方法,在该方法中创建对象 package test; / ...
- java 中操作字符串都有哪些类?(未完成)它们之间有什么区别?(未完成)
java 中操作字符串都有哪些类?(未完成)它们之间有什么区别?(未完成)
- java中的native方法和修饰符(转)
Java中的native修饰符 今天偶然看代码,发现别人有这样写的方法,并且jar里面有几个dll文件,比较奇怪,于是把代码打开,发现如下写法. public native String GSMMod ...
- Java中的四种权限修饰符及六种非访问修饰符(简识)
一.是哪四种访问权限修饰符呢? public > protected > [default] > private (公共的 ) (受保护的) (默认的) (私有的) 二.简单认识四种 ...
- Java中动态代理技术生成的类与原始类的区别 (转)
用动态代理的时候,对它新生成的类长什么样子感到好奇.有幸通过一些资料消除了心里的疑惑. 平时工作使用的Spring框架里面有一个AOP(面向切面)的机制,只知道它是把类重新生成了一遍,在切面上加上了后 ...
- Java中动态代理技术生成的类与原始类的区别
用动态代理的时候,对它新生成的类长什么样子感到好奇.有幸通过一些资料消除了心里的疑惑. 平时工作使用的Spring框架里面有一个AOP(面向切面)的机制,只知道它是把类重新生成了一遍,在切面上加上了后 ...
- 全面解释java中StringBuilder、StringBuffer、String类之间的关系
StringBuilder.StringBuffer.String类之间的关系 java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,在上一篇博文中我 ...
- Java基础知识(JAVA中String、StringBuffer、StringBuilder类的区别)
java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. 1.可变与不可 ...
随机推荐
- 高级语言虚拟机的一点理解,对比.NET和Java平台
最近学习了一些高级语言虚拟机的知识,在此对.NET平台和java平台做一个简单的比较.对java平台已经很熟了,所以此处只介绍.NET平台下的一些概念. 一.CLI 通用语言基础架构(Common L ...
- 【poj2741】 Colored Cubes
http://poj.org/problem?id=2741 (题目链接) 题意 给出n个骰子,每一面都有一种颜色,问最少更改多少个面的颜色可以使所有骰子通过旋转后完全相同. solution 迷之d ...
- POJ3048 Max Factor
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
- TYVJ1427 小白逛公园
时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着n个 ...
- PostgreSQL Reading Ad Writing Files、Execution System Instructions Vul
catalog . postgresql简介 . 文件读取/写入 . 命令执行 . 影响范围 . 恶意代码分析 . 缓解方案 1. postgresql简介 PostgreSQL 是一个自由的对象-关 ...
- PCRE Perl Compatible Regular Expressions Learning
catalog . PCRE Introduction . pcre2api . pcre2jit . PCRE Programing 1. PCRE Introduction The PCRE li ...
- no suitable HttpMessageConverter found for request type [java.lang.Integer]
今天在使用Spring Template的时候遇到了这个异常: no suitable HttpMessageConverter found for request type [java.lang.I ...
- 与number_format函数有关的一个bug?
最近在做一个模仿excel功能的在线项目.其中有一个功能,数据列表中的数据,到了最后一列都要进行总计.这本来没什么难度.直接从数据库取出数据后,进行foreach相加就行 了.这是如此的简单,以至于用 ...
- ionic的scroll的使用出现的问题
今天再写ionic的时候发现了一个问题,在使用ui-view的时候引用ion-scroll指令的时候初次加载的时候能能实现拖拽滚动,只能实现滚动鼠标滚轴滚动,然后各种调试,各种比较,终于发现原来是路由 ...
- BZOJ2827: 千山鸟飞绝
离散化坐标,每个坐标开一棵以鸟的编号为关键字的平衡树.每次插入时打2个标记,同时更新自身.这个方法比较显然,而且好写.正解好像用很迷的方法乱搞了一波,然后用线段树不打标记就做出来了,并不会. trea ...