在面向对象编程中,接口(Interface)和抽象类(Abstract Class)都是用于实现抽象化的机制,但它们在设计目的、语法规则和使用场景上有显著区别。以下是它们的核心区别:
1. 定义与关键字
-
接口:用
interface
关键字定义,是一种纯粹的抽象类型,仅声明方法规范(“做什么”),不提供具体实现(特殊情况除外,如Java 8+的默认方法)。
例:public interface Runnable { void run(); }
-
抽象类:用
abstract class
关键字定义,是包含抽象方法的类,既可以有抽象方法(无实现),也可以有具体方法(有实现)。
例:public abstract class Animal { abstract void eat(); void sleep() { ... } }
2. 继承/实现方式
-
接口:类通过
implements
关键字实现接口,一个类可以同时实现多个接口(支持多实现)。
例:class Dog implements Runnable, Serializable { ... }
-
抽象类:类通过
extends
关键字继承抽象类,一个类只能继承一个抽象类(多数语言如Java、C#支持单继承)。
例:class Dog extends Animal { ... }
3. 方法与实现
-
接口:
- 早期版本(如Java 7及以前)中,所有方法默认是
public abstract
(抽象方法,无实现)。 - 新版本(如Java 8+)允许定义
default
方法(有默认实现)和static
方法(静态实现),但核心仍以抽象方法为主。 - 方法访问修饰符只能是
public
(默认)。
- 早期版本(如Java 7及以前)中,所有方法默认是
-
抽象类:
- 可以包含抽象方法(用
abstract
修饰,无实现)和具体方法(有完整实现)。 - 方法访问修饰符可以是
public
、protected
等(但不能是private
,否则子类无法实现)。
- 可以包含抽象方法(用
4. 成员变量
-
接口:变量默认是
public static final
(常量),必须初始化,且不能被修改。
例:interface Constants { int MAX = 100; }
(等价于public static final int MAX = 100
) -
抽象类:变量可以是普通成员变量(非静态、非final),也可以是常量,允许被子类继承和修改(根据修饰符)。
5. 构造函数
- 接口:没有构造函数,因为接口不能被实例化,仅用于定义规范。
- 抽象类:有构造函数(用于子类初始化时调用),但抽象类本身不能被实例化。
6. 设计目的
-
接口:
强调“行为规范”,定义“能做什么”,用于实现多态和解耦。例如,Comparable
接口规定“可比较”的行为,任何类只要实现该接口就能被排序。
适合表示“不同类之间的共性行为”(如“可飞行”“可序列化”)。 -
抽象类:
强调“类的继承关系”,定义“是什么”,用于提取同类事物的共同属性和行为。例如,Animal
抽象类包含所有动物的共同方法(如eat()
),子类(Dog
、Cat
)继承后实现细节。
适合表示“is-a”关系(如“狗是动物”)。
总结对比表
特性 | 接口(Interface) | 抽象类(Abstract Class) |
---|---|---|
关键字 | interface | abstract class |
继承方式 | 多实现(implements ) | 单继承(extends ) |
方法实现 | 主要是抽象方法,可含默认方法(Java 8+) | 可混合抽象方法和具体方法 |
成员变量 | 只能是 public static final 常量 | 可包含普通变量、常量 |
构造函数 | 无 | 有(供子类调用) |
设计意图 | 定义行为规范(“做什么”) | 定义类的模板(“是什么”) |
如何选择?
- 若需要定义一组不相关类的共同行为(如“可打印”“可比较”),用接口。
- 若需要提取同类事物的共同属性和部分实现(如“动物”“形状”),用抽象类。
- 若既需要继承共性实现,又需要实现多行为规范,可同时使用(类继承抽象类 + 实现多个接口)。