java 抽象类与接口比较

两个极其相似的功能。

本文参考自深入理解Java的接口和抽象类

抽象方法

在了解抽象类之前,需要先了解一下抽象方法。

抽象方法是一种特殊的方法,它只有声明,没有具体的实现,抽象方法声明格式为:

1
abstract void func();

抽象方法必须用 abstract 关键字进行修饰。

抽象类

如果一个类含有抽象方法,那么这个类就称为抽象类。但是抽象类并不一定只包含抽象方法,它和普通类一样,同样可以拥有成员变量和普通的方法变量。抽象类声明格式如下:

1
2
3
abstract class Abstract {

};

抽象类用 abstract 关键字进行修饰。由于抽象类含有无具体实现的方法,所以不能用抽象类创建对象。

抽象类创建出来的目的就是为了被继承。如果一个抽象类不被继承,那么这个抽象类就没有意义。

接下来对比一下抽象类和普通类的区别(突然发现我还挺喜欢用表格):

抽象类 普通类
修饰字 必须为 abstract 或 protect (因为抽象类的目的为被子类继承) 均可
创建对象 不能被创建为对象 可以被创建为对象
子类继承的方法 子类必须实现父类的抽象方法,否则子类将被认为是抽象类 无限制

接口

接口泛指供别人调用的方法或函数,是对行为的抽象。接口的形式如下:

1
2
3
[public] interface Interface {

};

接口可以含有变量和方法,但是接口的变量将被隐式地指定为 public static final 变量且只能为该类型变量,方法将被隐式地指定为 public abstract 方法且只能为该类型方法,并且接口中的所有方法均不能有具体实现。

从以上定义可以看出,接口中的方法均为抽象方法。根据抽象类的定义,接口也是一种特殊的抽象类,它比抽象类更加 “ 抽象 ” ,并且一般不在接口中定义变量。

如果想让一个类遵循某组特定的接口,需要使用 implements 关键字。具体格式如下:

1
2
3
class ClassName implements Interfaces1,Interfaces2,[...] {

}

一个类可以遵循多个特定的接口。如果一个非抽象类遵循了某个接口,那么就必须实现该接口中的所有方法(接口是特殊的抽象类)。和抽象类的子类一样,对于遵循某个接口的抽象类,可以不实现该接口中的抽象方法。

抽象类和接口的区别

在语法层面上:

抽象类 接口
方法实现 可以提供成员方法的具体细节(可以有非抽象方法) 必须为public abstract 类型方法
成员变量 可以是任意类型 必须为public static final 类型变量
静态 可以含有静态代码块和静态方法 不能含有静态代码块和静态方法
继承 一个类只能继承一个抽象类 一个类可以实现多个接口

在设计层面上:

  1. 抽象类是对事物的一种抽象,即对类抽象,而接口是对行为的抽象。

抽象类是对整个类整体进行抽象,包括属性、行为等。但是接口是对类局部(行为)进行抽象。比如鸟和飞机,它们都是不同类的事物,但是具有共同的行为,那就是飞。因此我们可以将其设计成为两个类(Airplane、Bird)。但是我们不能把 飞 设计成类。因为飞是一个行为,并不是某一事物的抽象描述。因此我们需要将 飞 设计为一个 Fly 接口,该接口包含方法 fly(),然后鸟和飞机分别根据不同的需求去实现该接口。

从这里可以看出,继承是一个 “是不是” 的关系,接口是一个 “有没有” 的关系。如果一个继承了某个抽象类,那么子类必定为抽象类的种类。而接口则是实现有没有具备不具备的关系,如鸟是否能飞,能飞行则可以实现了该接口,不能飞则不需要实现该接口。

  1. 在设计层面上,抽象类可以作为许多子类的父类。是一种模板式设计;接口是一种行为规范,是一种辐射式设计。

模板式设计:子类为父类的实现。比如在写 PPT 时,我们可以直接找到一个 PPT 模板进行设计,改模板可以衍生出多个 PPT ,如果需要修改这些 PPT ,那么我们只要修改实现它们的模板即可。

辐射式设计:如果修改了接口中的方法,那么遵循该接口的方法必须全部进行修改。

这样就看出了两者之间的差异,假如说我们需要添加一个新的方法,对于抽象类,我们可以直接在抽象类中写一个该方法的具体实现,这样就不需要修改子类;但是对于接口则不行,因为接口中的方法全部分抽象方法,因此当添加(或修改、删除)一个方法时,遵循该接口的所有类均必须进行修改。

感谢您的支持
-------------本文结束感谢您的阅读-------------