接口默认方法是对行为契约的增强,非抽象类替代品;抽象类核心价值在于结构复用和继承约束:定义“能做什么”选接口,表达“是什么”选抽象类。

接口默认方法不是抽象类的替代品,而是对“行为契约”的增强;抽象类的核心价值在于“结构复用”和“继承约束”。选哪个,关键看你要解决的是“它能做什么”,还是“它本来就是什么”。
看设计意图:定义能力,还是构建类型
如果目标是统一一类行为规范,比如“可排序”“可序列化”“可重试”,就该用接口。即使加了 default 方法,它仍是契约——只是把通用实现作为可选补充,不改变“谁都能实现它”的本质。
抽象类则代表一种明确的类型归属。比如 BaseController、JdbcDao、WebSocketHandler,它们不只是“有某种能力”,而是“属于某类框架组件”,天然携带初始化逻辑、共享状态、生命周期钩子等。
- 接口适合描述“能干什么”:一个类可以同时是 Runnable、Closeable、AutoCloseable——互不冲突
- 抽象类适合表达“是什么”:一个类只能是 SpringBootServletInitializer 的子类,不能又是 HibernateEntity 又是 VertxHandler
看复用内容:逻辑片段,还是完整骨架
default 方法适合写短小、无状态、不依赖子类字段的通用逻辑,比如日志打点、参数校验模板、简单转换工具。但它不能访问 protected 字段,也不能调用子类构造器,更无法参与初始化流程。
立即学习“Java免费学习笔记(深入)”;
抽象类能做的事多得多:带参构造器初始化连接池、protected 成员缓存上下文、final 方法锁定执行顺序、模板方法固化流程(如 preProcess → doWork → postProcess)。
- 想复用一段独立工具逻辑(如格式化时间)→ 接口 default 方法够用
- 想复用一套带状态的执行流程(如事务开启→执行SQL→异常回滚→资源释放)→ 抽象类更稳妥
看继承关系:是否需要多实现
Java 单继承限制是硬约束。如果一个类 already extends Entity,但又要支持消息通知、权限校验、审计日志——这些能力彼此正交,就只能靠接口承载。
此时即便 default 方法写了重复逻辑(比如统一记录操作人),也比强行拉一个抽象父类更合理。否则会逼迫业务类做“继承妥协”,破坏领域模型清晰性。
- 需要多个正交能力(如 Audit、Trace、Retry)→ 接口 + default 方法是自然选择
- 需要统一基线行为 + 强制流程控制(如所有 DAO 必须走连接池、必须设超时)→ 抽象类不可替代
看演进风险:加功能会不会打破兼容性
给接口新增 default 方法,对已有实现类是二进制兼容的;但加抽象方法,就会导致所有实现类编译失败。抽象类新增具体方法,不影响子类;但新增抽象方法,同样强制所有子类修改。
不过,default 方法一旦被多个接口同时提供同名实现,而实现类又没显式覆盖,就会触发编译错误(“class inherits unrelated defaults”)。这种冲突在抽象类体系里不会出现——因为继承链唯一。
- 面向开放扩展(如插件体系)→ 接口 default 方法方便升级,但要警惕多继承冲突
- 面向内部强管控(如公司 SDK 基类)→ 抽象类更可控,版本升级路径更明确


















