方法遮蔽(Shadowing)是子类重新声明与父类同名的字段、静态方法或嵌套类,导致二者独立存在且编译期按引用类型决定访问目标;它非重写、不参与多态,需用this/super或类名显式区分访问层级。

方法遮蔽(Shadowing)在继承中不是覆盖,而是“同名但独立存在”。它不改变父类行为,也不参与多态,只是让子类声明的新成员在本类上下文中优先被访问。识别和应用的关键,在于分清“谁在调用”“从哪一层访问”“用什么语法显式指定目标”。
明确遮蔽发生的典型场景
遮蔽只发生在子类**重新声明**与父类同名的成员时,且该成员可以是字段、静态方法、嵌套类等——但不能是实例方法(那是重写/Override)。常见组合包括:
- 父类有
public String name = "A",子类又写public String name = "B"→ 字段遮蔽 - 父类有
static void log() { },子类也定义static void log() { }→ 静态方法遮蔽 - 父类有内部类
class Config { },子类再声明同名class Config { }→ 类遮蔽
通过引用类型判断实际访问对象
Java 中变量访问是静态绑定的:编译器看的是**引用的声明类型**,而不是运行时对象的实际类型。例如:
-
Parent p = new Child(); p.name→ 访问的是Parent.name -
Child c = new Child(); c.name→ 访问的是Child.name -
Parent p = new Child(); p.log()(log 是 static)→ 调用的是Parent.log(),因为静态方法不看实例
这种行为容易误以为是多态,实则是编译期就决定的遮蔽结果。
用 super 和 this 显式控制访问层级
当需要跨层级操作同名成员时,必须靠关键字明确指向:
-
this.name→ 当前类中声明的name(即使被遮蔽,也指子类自己的) -
super.name→ 父类中被遮蔽的那个name(仅限非 private 字段) -
Parent.name(静态)或Child.name→ 直接通过类名访问对应静态成员,避免歧义
注意:super 不能用于静态上下文;private 成员不可被子类访问,自然无法被遮蔽或显式引用。
实战中快速识别遮蔽是否发生
遇到逻辑异常(比如修改了子类字段,但父类引用读出来没变),按以下顺序排查:
- 检查父子类是否都声明了同名字段(尤其 public / protected 实例变量)
- 确认你用的是对象引用还是子类实例引用,再对照编译时类型查字段归属
- 在子类方法中打印
this.name和super.name的值,验证是否真为两个独立存储 - IDE 中将鼠标悬停在变量名上,通常会提示“shadows field from superclass”,这是最直接的信号

















