应优先用接口表达“能做什么”,用抽象类表达“是什么”;需共享状态或构造逻辑时选抽象类,需多行为组合或契约约束时选接口;JDK8+中default方法不改变接口本质。

选抽象类还是接口,关键看你想表达“它是什么”,还是“它能做什么”。前者用抽象类,后者用接口。
看是否需要共享状态或构造逻辑
如果多个子类要共用字段(比如 name、id)、需要统一初始化流程,或者有通用的具体方法(比如 saveLog()、validate()),那就该用抽象类。它允许定义构造方法、普通成员变量和非抽象方法。
- 抽象类可以有 protected String name;,子类直接继承使用
- 抽象类可提供 public void sleep() { System.out.println(name + " is sleeping"); }
- 接口无法保存状态,所有字段自动是 public static final,只能是常量
看是否需要多行为组合
一个类往往不止有一种能力——比如“能飞”“能跑”“能充电”。Java 不支持多继承,但允许一个类实现多个接口。这时接口就是唯一选择。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- class Drone implements Flyable, Runnable, Chargeable —— 合理且常见
- 若强行用抽象类模拟,就得把所有行为塞进一个父类,违反单一职责,也堵死其他继承路径
- 接口之间还能继承:interface SmartDevice extends Chargeable, Networked
看设计意图是模板复用还是契约约束
抽象类偏向“模板”:你继承我,就默认获得我的骨架和部分血肉;接口偏向“合同”:你签了我,就必须履行几个明确义务,至于怎么干,全由你定。
立即学习“Java免费学习笔记(深入)”;
- 数据库操作模块常用抽象类封装 getConnection()、close() 等公共逻辑,子类只专注 buildQuery()
- 支付系统用接口定义 pay()、refund(),让微信支付、支付宝、银行卡各自实现,互不干扰
- 当不同领域对象(人、机器人、无人机)都需要“移动”,用 Movable 接口比硬拉一个共同父类更自然
注意 JDK8+ 的模糊地带
接口支持 default 和 static 方法后,也能提供简单实现,但这不改变它的本质——它仍是行为契约,不是状态容器。别为了少写几行代码就把本该是接口的规范改成抽象类。
- 接口里的 default void stop() { System.out.println("stopping"); } 是兜底行为,不是核心状态管理
- 抽象类中的 private void initCache() 或 protected List<String> history; 仍无可替代
- 如果发现抽象类里全是抽象方法,没有字段也没有具体逻辑,那它大概率该重构成接口

















