接口和抽象类适用场景不同:抽象类用于复用骨架和表达is-a关系,适合有共性状态和固定流程的层级结构;接口用于定义契约和表达can-do关系,适合叠加能力、解耦协作及跨类型统一行为。

接口和抽象类不是“哪个更好”,而是“用在哪更合适”。关键看你要解决的是“复用骨架”还是“定义契约”。
看设计意图:是“是什么”还是“能做什么”
抽象类表达 is-a 关系,比如“PDF导出器是一个报表导出器”,它承载共性状态(如配置、日志对象)和流程骨架(查数据→加工→写文件)。
接口表达 can-do 关系,比如“这个类能序列化”“这个类可取消”,它不关心你是谁,只约定你能提供什么行为。
一个类只能继承一个抽象类,但可以实现多个接口。这意味着:要建层级结构,用抽象类;要叠加能力或解耦协作,用接口。
看代码结构:能放什么、怎么组织
抽象类允许:
立即学习“Java免费学习笔记(深入)”;
- 定义实例变量(比如
protected String exportPath) - 写构造器(用于初始化共享资源)
- 混用抽象方法和具体方法(80%逻辑统一,20%由子类定制)
- 使用任意访问修饰符(
private工具方法、protected钩子方法)
接口只允许:
- 常量(自动
public static final) - 抽象方法(自动
public abstract) - 默认方法(
default,提供可选实现) - 静态方法(
static,工具型逻辑,直接通过接口调用)
看典型场景:什么情况下该选哪一个
优先用抽象类的情况:
- 多个子类有大量重复字段和通用方法(如数据库操作中的连接管理、事务模板)
- 业务流程固定,但某些步骤因类型而异(如支付流程:校验→生成流水→调网关,只有网关地址和参数不同)
- 需要在父类中持有状态(如缓存、上下文、计数器)
优先用接口的情况:
- 跨不同类体系统一行为(如
Comparable、Runnable、Closeable) - 为第三方类扩展能力,又不能改它的继承链(比如让一个已有实体类支持 JSON 序列化)
- 团队协作中定义服务契约(如后端定义
PaymentService接口,前端只依赖它,不关心是微信还是支付宝实现)
特别注意的混合用法
抽象类可以实现接口,且不必实现全部方法——这种“便利类”很实用。例如:
定义接口 Exporter 含 export() 和 validate();
写一个抽象类 BaseExporter 实现 export() 的通用逻辑,把 validate() 留空或设为抽象;
具体子类只需专注实现 validate() 即可。
这样既享受了接口的契约约束,又避免了每个实现类都重写模板代码。


















