选接口还是抽象类,关键看想表达“它能干什么”还是“它本来就是什么”:无继承关系但需统一能力用接口,同类别且需共享状态/逻辑用抽象类;接口支持多实现和渐进扩展,抽象类适合封装共用字段、构造逻辑与模板方法。

选接口还是抽象类,关键看你想表达“它能干什么”,还是“它本来就是什么”。业务场景不同,侧重点就不同,硬套语法规则反而容易出错。
看关系:是“能做这件事”,还是“天生就属于这一类”
如果多个类之间没有继承关系,但需要统一对外提供某种能力,优先用接口。比如支付渠道、日志输出、消息通知——微信支付和短信服务完全不相干,但都“能发起通知”,那就定义一个 Notifier 接口。
如果一组类明显属于同一类事物,有共用状态(如商户ID、配置开关)、共享初始化逻辑(如加载密钥、连接池),且后续大概率要扩展子类,就用抽象类。比如所有银行通道都继承 BankChannel,它可封装通用验签、重试、幂等处理逻辑。
看复用:要不要共享字段、构造逻辑或具体方法
抽象类能带成员变量、构造方法、protected 方法,适合把重复的初始化、工具逻辑、中间状态提前写好。例如:
- 所有风控策略都需要读取同一个规则引擎上下文 → 抽象类里声明 protected RuleContext context,构造时注入
- 多个导出服务都要统一加文件头、压缩、落盘路径校验 → 这些可直接写在抽象类的 export() 模板方法里
接口不能存状态,也不能初始化对象。哪怕 Java 8 后支持 default 方法,也只是行为契约的补充,不适合放含状态或需子类配合初始化的逻辑。
看扩展:是否需要一个类同时具备多种不相关能力
Java 只允许单继承,但允许实现多个接口。当业务要求一个类“既能审核、又能导出、还能被审计”,这三种能力彼此无关,就该拆成 Auditable、Exportable、AuditLoggable 三个接口,让具体类按需组合。
若强行用抽象类,就得设计出一个超级父类,或者不断调整继承链,很快就会陷入“菱形继承”困境,维护成本飙升。
看演进:未来会不会频繁新增能力,又不想改所有实现类
接口更适合渐进式增强。比如原来只有 query(),后来要加缓存穿透防护,就可以加个 default 方法 queryWithBloomFilter(),老实现类自动获得新能力,无需改动。
抽象类加新方法则风险更高:加普通方法,子类可能意外继承到不该用的逻辑;加抽象方法,所有子类必须立刻响应,上线节奏被卡住。所以框架底层基类升级往往比接口更谨慎。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











