抽象类用于表达“is-a”关系并强制子类实现特定行为,支持字段、构造器和protected方法;普通类可直接实例化,适合独立对象;接口侧重能力契约。

抽象类和普通类不是风格偏好,而是设计意图的体现。选错会导致后期扩展困难、约束失效或代码重复。
看这个类能不能直接用
如果逻辑上它本身就不该被 new 出来,比如“形状”“支付方式”“消息处理器”,那就必须是抽象类。普通类必须能独立创建实例,否则编译不通过。
- 抽象类:不能 new,只能被继承,子类实现完抽象方法后才能实例化
- 普通类:可以直接 new,适合表示一个完整、可运行的对象,如 Person、Order、Logger
看要不要强制子类做某件事
当多个子类必须统一提供某个行为(比如 start()、validate()、render()),但各自实现不同,抽象类里的抽象方法就是最直接的约束手段。
- 抽象类中声明 public abstract void start(); → 子类不重写就编译失败
- 普通类只能提供默认实现,子类可以忽略、覆盖或不覆盖,无法保证行为存在
- 接口也能强制,但不能带构造逻辑、成员变量或 protected 工具方法
看有没有共用状态或基础功能
抽象类可以有字段、构造器、protected 方法、通用校验逻辑等,子类自动继承复用;普通类虽然也能被继承,但无法阻止子类绕过关键流程。
- 例如 BaseDao 抽象类封装 getConnection() 和 close(),子类只专注 SQL 和映射
- 普通类做不到“必须调用父类初始化逻辑”,也难以统一拦截或增强
- 工具类(全是 static 方法)用普通类更合适,无需抽象
看继承关系是否符合“is-a”且需要单根控制
抽象类天然表达“是一种”的层级关系,并支持单继承下的结构收敛。如果你希望所有子类共享一套初始化规则、生命周期钩子或内部状态管理,抽象类比接口+普通类组合更清晰。
- Vehicle → Car / Bike / Truck:适合抽象类,共用 speed、startLogic、fuelLevel 等
- Runnable / Comparable / Serializable:适合接口,关注能力契约,不涉及状态或构造
- 一个类只能继承一个抽象类,但能实现多个接口——这是设计时就要权衡的边界
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











