接口定义行为契约(“能做什么”),仅含抽象方法和常量;抽象类定义类型身份与部分实现(“是什么+怎么做”),支持构造器、字段及多种访问修饰符。

语法层面的核心差异
定义方式不同:接口用 interface 声明,只能包含 public abstract 方法(Java 8+ 可含 default 和 static 方法)、public static final 字段;抽象类用 abstract class 声明,可含任意访问修饰符的方法、构造器、实例字段、静态字段、代码块,以及 abstract 和具体实现方法。
继承机制不同:类只能单继承一个抽象类,但可实现多个接口;接口之间支持多继承(用 extends 组合多个父接口)。
构造器与实例化:抽象类可定义构造器(供子类调用),但不能直接实例化;接口不能有构造器,也不允许实例化。
语义层面的职责划分
接口表达“能做什么”:聚焦行为契约,不关心实现细节或状态。例如 Runnable 不说明线程如何调度,只承诺提供 run() 行为;Comparable 不限定比较逻辑,只约定可被排序。
抽象类表达“是什么 + 部分怎么做”:既定义类型身份(如 Animal 是一种生物),又封装共性实现(如 breath() 的默认逻辑)和共享状态(如 age 字段)。它天然带有“is-a”关系的语义强度。
一个类实现多个接口,表示它具备多种独立能力(“can-do”);继承抽象类,则意味着它属于该类所代表的类别体系(“is-a”),并复用其骨架。
设计意图与使用场景判断
优先选接口当需要解耦行为契约:
- 定义服务规范(如
PaymentService),让不同支付渠道(微信、支付宝)自由实现 - 支持跨层级、跨领域的能力组合(如一个类同时是
Serializable、Cloneable、Validatable) - 适配已有类(无法修改源码时,用接口+适配器模式桥接)
优先选抽象类当需要共享状态或强制统一结构:
- 框架基类(如 Spring 的
AbstractController提供请求预处理、视图解析等模板逻辑) - 具有共同字段和基础行为的类型族(如
Shape抽象类含color、area()抽象方法 +toString()默认实现) - 需控制子类初始化流程(通过抽象类构造器或
init()模板方法约束)
演进性与兼容性考量
接口更脆弱于扩展:Java 8 前,给接口新增方法会导致所有实现类编译失败;虽引入 default 方法缓解,但若已有实现类重写了同名方法,可能引发意料外的行为覆盖或二义性。
抽象类扩展更可控:新增具体方法不影响子类;新增抽象方法虽也需子类响应,但可通过提供空实现或模板方法降级影响。添加字段也不会破坏二进制兼容性(只要不改变已有字段语义)。
因此,长期演进的公共 API 更倾向用抽象类封装核心骨架,用接口暴露稳定契约;高频迭代的策略点(如算法插件)更适合接口驱动。










