抽象类封装共性状态与可复用逻辑,接口定义“能做什么”的能力契约;类可单继承抽象类并多实现接口,结合default方法增强灵活性,且需严守职责边界避免混淆。

用抽象类封装共性,用接口定义能力
抽象类适合放那些多个子类共享的状态和可复用逻辑,比如公共字段、初始化流程、部分已实现的方法;接口则聚焦于“能做什么”,比如Runnable、Serializable、Loggable。一个类继承抽象类的同时实现多个接口,就自然获得了状态+逻辑+能力的组合。
例如:
abstract class AbstractOrder {<br>
protected final String orderId;<br>
protected AbstractOrder(String orderId) { this.orderId = orderId; }<br>
protected void validate() { /*通用校验逻辑*/ }<br>
}
class PaymentOrder extends AbstractOrder implements Serializable, Comparable<paymentorder>, JsonSerializable { ... }</paymentorder>
多态调用面向接口,运行时依赖具体子类
外部代码用接口类型声明变量,既松耦合又便于替换;而对象实际由继承抽象类的具体子类构造,复用其内部逻辑。
-
编译期看接口:如
JsonSerializable serializer = new PaymentOrder(...);,调用方只依赖契约 -
运行期靠子类:
PaymentOrder继承AbstractOrder,自动获得订单ID管理、基础校验等能力 - 新增
RefundOrder时,只需继承同一抽象类、实现相同接口,就能无缝接入原有处理链
用 default 方法把轻量行为下沉到接口
JDK 8+ 的 default 方法让接口也能提供简单实现,避免重复代码,又不破坏接口的契约本质。
比如定义:
interface Loggable {<br>
default void logStart() {<br>
System.out.println("[" + getClass().getSimpleName() + "] started");<br>
}<br>
}
所有实现该接口的类(无论是否继承某个抽象类)都能直接调用
logStart()。需要定制时,子类重写即可,不影响其他实现。
避免职责混淆的边界提醒
协同有效的前提是分工清晰:
- 抽象类不应为凑功能而强行实现某个接口,除非它天然具备该行为且能给出合理默认实现
- 接口之间继承仅在语义明确的“is-a”关系下使用,比如
Queue extends Collection,而不是为了合并方法签名 - 一个类
extends 抽象类 implements 接口1, 接口2, 接口3是标准做法;但如果抽象类里已经塞满业务方法,接口只剩空壳,说明抽象层级出了问题
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











