extends 应严格遵循“is-a”语义,如 Car extends Vehicle;避免误用组合关系或语义断裂;父类需抽象通用概念,提取共用字段、方法及模板骨架;合理使用访问修饰符,构造器须显式调用 super() 确保状态初始化。

用 extends 建立清晰的类层次结构,核心是让继承关系真实反映“是什么”(is-a)的语义,并控制好代码复用的粒度。不是所有相似都能继承,关键在抽象得准、边界划得清。
紧扣“is-a”关系设计父类
只有当子类在业务或领域模型中天然属于父类的一种时,才适合用 extends。比如:
- ✅ 合理:Car extends Vehicle(汽车是一种交通工具)
- ❌ 不合理:Car extends Engine(汽车有一个引擎,不是“一种引擎”,该用组合)
- ❌ 不合理:User extends DatabaseConnection(用户不是数据库连接,语义断裂)
父类名称应是通用概念(如 Shape、Payment、Document),字段和方法要代表所有子类共有的本质特征,而非临时拼凑的公共字段。
把真正共用的逻辑上提到父类
识别多个类中重复出现、且行为一致的代码,再迁移。常见可提取项包括:
- 基础状态字段:如
protected String id;、protected LocalDateTime createdAt; - 通用行为方法:如
public void validate() { ... }、protected void logAction(String action) { ... } - 模板方法骨架:定义流程框架,把变化点留给子类实现(配合
abstract或final方法)
避免把仅两个子类用到的方法硬塞进父类——那会污染其他子类的 API,也违背开闭原则。
用访问修饰符守住继承边界
父类成员的可见性直接决定子类能拿到什么、怎么用:
-
public:对外暴露,子类可用,外部也可调用 -
protected:专为继承设计,子类可直接访问,包外非子类不可见 -
private:不参与继承,子类完全不可见(但可通过protected的 getter/setter 间接访问) - 默认(包级私有):仅同包子类可用,跨包子类拿不到
推荐策略:字段尽量 private + protected 的 getter/setter;核心可复用方法设为 protected;对外接口保持 public 稳定。
构造器与 super() 要显式可控
子类构造器必须第一行调用 super(...),这是保证父类状态正确初始化的前提:
- 若父类只有带参构造器,子类每个构造器都必须显式写
super(参数) - 不写
super()时,编译器自动补super()—— 所以父类必须有无参构造器,否则编译失败 - 禁止在普通方法里调用
super(),只允许在构造器中使用
这一步看似琐碎,实则决定了整个继承链的状态可靠性。跳过或误用,轻则字段为 null,重则逻辑错乱。

















