extends本质是“共享+可重定义”,子类通过它访问父类非private成员,每个实例独立持有父类字段;需用super初始化父类变量,避免null;慎用static和同名字段隐藏。

extends 是 Java(以及 TypeScript、Kotlin 等语言)中实现类继承的核心关键字,它让子类能复用父类的字段、方法,并支持多层嵌套构建清晰的类层级。实战中关键不在于“能否继承”,而在于“如何设计继承逻辑,使父类变量真正参与子类行为”。
明确 extends 的本质:不是复制,而是“共享+可重定义”
子类通过 extends 获得对父类 非 private 成员 的访问权,但父类变量(字段)在每个子类实例中仍独立存在——不是“拷贝一份”,而是“每个对象都有一份属于自己的父类部分”。这意味着:
- 父类中声明为 protected 或 public 的变量,子类可直接读写(如
this.name); - 父类 private 变量不可直接访问,必须通过 public/protected 方法间接操作;
- 子类可定义同名变量(隐藏父类字段),但通常应避免——这会破坏继承语义,引发歧义。
实战:用父类变量驱动子类差异化行为
真正体现“逻辑继承”的,是让父类变量成为子类方法执行路径的依据。例如设计一个基础图形类及其子类:
class Shape {
protected String color = "white";
protected boolean filled = false;
<pre class="brush:php;toolbar:false;">public void describe() {
System.out.println("Color: " + color + ", Filled: " + filled);
}
}
class Circle extends Shape { private double radius = 1.0;
public Circle(String color, boolean filled, double radius) {
this.color = color; // 直接赋值父类 protected 字段
this.filled = filled;
this.radius = radius;
}
@Override
public void describe() {
super.describe(); // 复用父类逻辑
System.out.println("Type: Circle, Radius: " + radius);
}
}
class Rectangle extends Shape { private double width = 1.0; private double height = 1.0;
public Rectangle(String color, boolean filled, double width, double height) {
this.color = color;
this.filled = filled;
this.width = width;
this.height = height;
}
@Override
public void describe() {
super.describe();
System.out.println("Type: Rectangle, Area: " + (width * height));
}
}
这里 color 和 filled 是父类变量,但它们直接影响每个子类 describe() 的输出内容——逻辑从父类定义(统一描述结构),由子类补充(特有属性),而变量本身被共同维护。
注意构造器链:确保父类变量被正确初始化
子类构造器必须显式或隐式调用父类构造器(super(...))。若父类无无参构造器,子类必须用 super 传递参数:
class Shape {
protected String color;
protected boolean filled;
<pre class="brush:php;toolbar:false;">public Shape(String color, boolean filled) {
this.color = color;
this.filled = filled;
}
}
class Triangle extends Shape { private double base, height;
// 必须调用 super,否则编译报错
public Triangle(String color, boolean filled, double base, double height) {
super(color, filled); // ← 关键:把值传给父类变量
this.base = base;
this.height = height;
}
}
漏掉 super(...) 或调用位置不在第一行,会导致父类字段未初始化(如 color 为 null),后续逻辑出错。
进阶:配合 final / static 辨析继承边界
理解哪些变量不该被“逻辑继承”同样重要:
-
final 实例变量:可在子类构造器中通过
super初始化,但之后不可修改——适合定义子类专属常量(如Circle.PI); - static 变量:属于类而非实例,子类继承的是“同一份静态变量”,修改会影响所有子类——慎用于需隔离状态的场景;
- 若父类变量逻辑复杂(如需校验、联动更新),应封装为 protected setter,而非暴露字段本身。
不复杂但容易忽略。










