在Java语言中,abstract class和interface是抽象类定义的两种机制。

由于这两种机制的存在,让Java有了强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性,甚至可以相互替换,因此有的人在进行抽象类定义时对于abstract class和interface的选择显得比较随意。其实,对于abstract class 和interface这两者之间还是有很大区别的,对于它们的选择也反映出对它们的理解。

理解抽象类

在面向对象中,所有的类都是通过对象来进行描述的,但是,反过来,并不是所有的类都是描述对象的,如果一个类没有用足够的信息来描述一个详细的对象,那么这个类就是抽象类,这个抽象类往往是对对象进行分析设计而得出的一个抽象的概念。是对看上去不同,但是本质上没有任何差别的一类对象的抽象概念。就像我们喜欢的一些东西,像猫、狗、鸟,它们都属于动物,但是它们各自又有自己的特征。所以在面向对象中,我们可以将它们固定的一组的行为抽象出来,但是这些行为又有自己的实现方式,它们的特征是不同的。这些抽象出来的综合在一起就构成了抽象类,而对这组中任意的抽象的对象进行具体的描述,这样就构成了派生类。还是用猫、狗、鸟来说,它们都会叫,把这个叫抽象出来,建立抽象类,下面具体的类,继承这个类,对类猫、狗、鸟来进行具体描述,这个叫是怎么叫的,是如何表达出来的。

abstract class 和interface分析

在语法上,abstract class 和interface的写法是不同的。下面来具体说明:

abstract class :

[java] view plain copy

<span style="font-size:18px;">abstract calss Door{

public abstract void Open();

public abstract void Close();

}

class Door1 extends Door

{

public void Open(){

Sy("Door1 Open");

}

public void Close(){

Sy("Door1 Close");

}

public void Broken(){

Sy("Door1 Broken");

}

}</span>

interface:

[java] view plain copy

<span style="font-size:18px;">public interface Door{

public static final int id=1;

public void Open();

public void Close();

}

public cass Door1 implements Door{

public void Open(){

Sy("Door1 Open");

}

public void Close(){

Sy("Door2 Close");

}

}</span>

在abstract class方式中,可以有自己的数据成员,也可以有非 abstract的成员方法,而在interface方式的实现中,只能够有静态的不能被修改的数据成员,也就是必须是static final 的,但是在interface中一般不定义数据成员,所有的成员方法都是abstract的。从某种意义上来说,interface其实是一种特殊的 abstract class。

如果此时对于Door这个东西,不仅具有这些功能,还需要增加一个报警的功能,那么,此时我们又应该如何设计呢?

abstract class

[java] view plain copy

<span style="font-size:18px;">abstract calss Door{

public abstract void Open();

public abstract void Close();

public abstract void Alarm();

}

class Door1 extends Door

{

public void Open(){

Sy("Door1 Open");

}

public void Close(){

Sy("Door1 Close");

}

public void Alarm(){

Sy("Door1 Alarm");

}

}</span>

interface:

[java] view plain copy

<span style="font-size:18px;">public interface Door{

public static final int id=1;

public void Open();

public void Close();

public void Alarm();

}

public cass Door1 implements Door{

public void Open(){

Sy("Door1 Open");

}

public void Close(){

Sy("Door2 Close");

}

}</span>

这种方法虽然也能实现,但是在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的对象会因为"报警器"这个概念的改变而改变。另外,举个例子,如果有扇门,他没有报警的功能,只有开和关,此时的抽象类就不再起作用,对它没作用,要么重新写抽象类,要么都写在一个类中,抽象思想就不再有作用。但是这丝毫不会影响接口,它同样能实现想要的效果。

再看,既然说Open、Close和Alarm属于两个不同的概念,我们就可以把它们分别定义在代表这两个概念的抽象类中。定义方式有:

第一:这两个概念都使用 abstract class 方式定义;

第二:两个概念都使用interface方式定义;

第三:一个概念使用 abstract class 方式定义,另一个概念使用interface方式定义。

此时,问题又来了,对于Java来说,Java语言不支持多重继承,所以都使用abstract class方式来定义是不可行的。但是后面两种方式都是可行的。

如果都使用interface方式来定义,那么就反映出对于那种特殊的AlarmDoor本质上到底是Door还是报警器?我们通过对其分析发现AlarmDoor在本质上和Door是相同的,都是Door,只是这个AlarmDoor还有报警的功能,但是我们现在又这么设计,合理吗?那么我们该如何来设计实现,明确的反映出我们的意思呢?

abstract class在Java语言中表示一种继承关系,它反映出来什么是什么的一个关系。所以对于Door这个概念,我们应该使用abstarct class方式来定义。对于AlarmDoor的报警功能,只能说除了共性外,它还有一个特性,那就是报警,这样,就可以通过interface方式定义。即:

[java] view plain copy

<span style="font-size:18px;">abstract class Door{

abstract void open();

abstract void close();

}

interface Alarm{

void alarm();

}

class AlarmDoor extends Door implements Alarm{

void open(){

Sy("AlarmDoor Open");

}

void close(){

Sy("AlarmDoor Close");

}

void alarm(){

Sy("AlarmDoor Alarm");

}

}</span>

这样,我觉得就能够明确的反映出这个问题的理解和我们要如何解决如何设计的意图。

小结

相同点:

第一:接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他的类实现和继承。

第二:接口和抽象类都是可以包含抽象方法的,实现接口或是继承抽象类的普通子类都必须实现这些抽象方法。

不同点:

第一:接口只能包含抽象方法,不能包含已经提供实现的方法;抽象类则完全可以包含普通的方法

第二:接口不能定义静态方法;抽象类可以定义静态方法。

第三:接口里面不能够包含初始化块;但是抽象类里面则完全可以包含初始化块

第四:一个类最多只能有一个直接父类,包括抽象类;但是一个类可以直接实现多个接口,通过实现多个接口可以弥补Java中的单继承的不足。

第五:实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。

总结

abstract class 和 interface 是 Java语言中的两种定义抽象类的方式,它们之间存在很大的相似性,都能够实现相应的需求功能,但是对于它们的选择,往往反映出我们对于问题理解和对于设计意图的反映是否正确、合理。同时他们表现的也是两种不同的关系,abstract class表示的是“什么是什么”的一种关系,而interface表示的是“什么像什么”的关系。这就需要我去慢慢总结体会。

相关推荐