选抽象类还是接口,关键看设计意图:表达“它是什么”用抽象类,体现is-a关系并共享状态与逻辑;表达“它能做什么”用接口,体现can-do关系并定义跨类族的行为契约。

选接口还是抽象类,关键看你想表达“它是什么”,还是“它能做什么”。不是语法上能不能,而是设计上该不该。
当需要表达“是什么”关系时,用抽象类
如果多个类天然属于同一类事物,有共用的状态、构造逻辑或默认行为,抽象类更合适。它提供继承骨架,让子类共享实现细节。
- 有共同字段要初始化?抽象类可以定义
protected String name,并用构造器传参赋值 - 多个子类复用同一段逻辑?比如
sleep()方法所有动物都一样,直接在抽象类里写死 - 需要模板方法控制流程?比如
prepare() → cook() → serve(),其中cook()抽象,其余具体,这是抽象类的经典用法
当需要表达“能做什么”能力时,用接口
如果行为和类的本体无关,不同类(甚至毫无继承关系)都需要这个能力,接口就是标准答案。它不侵入原有继承链,只附加契约。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 一个类既要可序列化,又要可比较,还要可克隆?只能靠
implements Serializable, Comparable, Cloneable - 支付系统里,微信、支付宝、银行卡实现
Payable,但它们根本不是同一种“东西”,只是“都能付钱” - Java 8+ 的
default方法让你能在不破坏已有实现的前提下,给接口新增通用行为(比如logging())
两者配合使用是常见且合理的做法
真实项目中,接口和抽象类经常共存。接口定义能力边界,抽象类在某条继承线上做实现收敛。
立即学习“Java免费学习笔记(深入)”;
- 比如定义
Drawable接口规范绘图行为,再为 Swing 组件建一个AbstractComponent抽象类,封装事件监听、坐标管理等共性 - 又如
Runnable是接口,但框架内部可能提供AbstractTask抽象类,预置线程上下文、超时处理等逻辑供业务扩展
一个快速判断口诀
问自己三个问题:
- 这些类是不是“同一类东西”?→ 是,倾向抽象类
- 这个功能是不是“额外加的能力”,和其他类没关系?→ 是,倾向接口
- 有没有可能将来要让一个类同时拥有多种不相关的功能?→ 是,必须用接口

















