抽象类的核心是提炼共性、约束行为、复用逻辑:1.有稳定共性逻辑(如日志、校验)时上提至抽象类;2.有统一接口但实现各异(如makesound)时定义抽象方法;3.需共享状态或构造流程(如共用字段、初始化逻辑)时使用抽象类。

抽象类和具体类的划分,核心在于“谁该定义契约,谁该落地执行”。抽象类不是为了替代具体类而存在,而是为了一组具体类提炼共性、约束行为、复用逻辑。
看是否有稳定共性逻辑需要复用
如果多个具体类重复实现相同功能(比如日志记录、参数校验、资源初始化),这些逻辑就该上提到抽象类里。子类继承后直接使用,不用再写一遍。
- 例如:所有 HTTP 处理器都要解析请求头、设置响应编码、记录耗时——这些可放在
AbstractHttpHandler中实现 - 而
JsonHandler和XmlHandler只需专注各自的数据解析逻辑,即重写抽象方法parseRequestBody()
看是否有一致的行为接口但实现各异
当父类能明确“必须有这个方法”,却无法给出统一实现时,就用抽象方法定义契约。这比在具体类里各自起名更规范,也便于多态调用。
- 比如
Animal类不能写死makeSound()的实现,但所有子类都得提供自己的叫声 - 调用方只需面向
Animal类型编程:animal.makeSound(),运行时自动分派到猫、狗、鸟的具体实现
看是否需要共享状态或构造流程
抽象类可以声明字段、提供带参构造方法、含初始化逻辑——这些是接口做不到的。如果子类共用某些属性(如 ID、创建时间、配置对象),或构造时必须执行固定步骤(如连接池预热、配置加载),抽象类就是自然选择。
-
BaseService可持有一个DataSource字段,并在构造时检查其有效性 - 子类如
UserServiceImpl或OrderServiceImpl直接复用该字段和校验逻辑,无需重复声明和检查
避免常见误用
不是所有“看起来像父类”的类都该是抽象类。以下情况更适合用具体类或接口:
- 类本身可以被实例化(如工具类
StringUtils),就不该设为抽象 - 只定义能力、不管理状态,且需要多实现(如一个类既要可序列化又要可缓存),优先用接口组合
- 仅为了“分类命名”而抽象(如把
Car抽成Vehicle,但Vehicle没有任何抽象方法或复用逻辑),属于过度设计
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











