抽象类的设计核心在于“定义契约+提供复用”:抽象方法强制子类实现行为边界,非抽象方法封装共享逻辑;关键在判断“该不该放”,需兼顾稳定性与扩展性。

抽象类的设计核心在于“定义契约 + 提供复用”,抽象方法划定子类必须实现的行为边界,非抽象方法封装可共享的逻辑或默认实现。关键不是“能不能放”,而是“该不该放”——要围绕继承体系的稳定性和扩展性来判断。
抽象方法:聚焦变化点与强制契约
抽象方法应代表子类间行为差异大、无法统一实现的核心职责。比如图形绘制系统中,draw() 和 getArea() 通常设计为抽象方法,因为不同图形(Circle、Rectangle)的绘制逻辑和面积计算方式本质不同,父类无法也不该提供默认实现。
- 只在真正需要子类差异化实现的地方声明抽象方法
- 避免把临时未实现的方法草率设为抽象——先考虑是否该由具体子类承担,或能否用默认方法/模板方法替代
- 抽象方法不写方法体,且所在类必须用 abstract class 声明
非抽象方法:封装稳定逻辑与通用能力
非抽象方法用于沉淀子类共用的代码,例如日志记录、参数校验、状态初始化、组合调用等。它们增强复用性,同时减少重复代码和出错可能。
- 模板方法模式 是典型用法:定义算法骨架(如 process()),调用若干抽象/钩子方法,子类只需填空关键步骤
- 工具型方法(如 validateInput(String s)、formatTimestamp())适合放在抽象类中供所有子类直接使用
- 可被 final 修饰以防止子类意外覆盖关键逻辑
搭配 protected 成员与构造器控制
抽象类常需为子类提供受保护的数据或初始化支持。字段建议用 protected(而非 public 或 package-private),构造器应明确完成基础状态设置(如配置加载、资源预分配),并可接受子类传入必要参数。
- 避免在抽象类中暴露 public 字段;用 protected 字段 + protected getter 更安全
- 抽象类构造器不能被实例化,但会被子类 super() 调用,是执行公共初始化的唯一可靠位置
- 若构造逻辑复杂,可配合 protected init() 钩子方法,供子类在构造后进一步定制
警惕过度设计与职责混淆
抽象类不是“万能基类”。当非抽象方法越来越多、逻辑越来越重,就要反思:是否正在把工具类、服务类、甚至业务流程控制器塞进抽象类?这会降低可测试性与可维护性。
- 单一职责优先:抽象类应只负责定义一类对象的共性结构,不承担跨领域职责(如网络请求、数据库操作)
- 优先组合而非继承:若某功能(如加密、缓存)多个抽象类都需要,更合适的方式是通过字段组合一个独立组件
- Java 8+ 可考虑接口默认方法处理简单共享行为;抽象类更适合需要字段、构造器或复杂初始化的场景
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











