变量遮蔽是指内层作用域中同名变量覆盖外层变量可见性,但不修改外层变量;常见于参数/局部变量遮蔽成员变量、内部类字段遮蔽外部类字段,需用this或Outer.this显式访问被遮蔽变量。

Java 中的变量遮蔽(shadowing)是指在某个作用域内声明的变量,其名称与外层作用域中已存在的变量相同,从而“遮蔽”了外层变量,导致在该作用域内无法直接访问被遮蔽的变量。
什么是变量遮蔽
变量遮蔽发生在局部变量、方法参数或内部类字段与外部类字段、父类字段或更外层作用域中的变量同名时。此时,内层变量会覆盖(即遮蔽)外层同名变量的可见性,但外层变量并未被修改或删除,只是暂时不可见。
注意:遮蔽不等于重写(override),它只影响名称解析,不涉及多态或运行时绑定;也不同于变量隐藏(hiding),后者通常指子类静态字段遮蔽父类同名静态字段(属于静态绑定范畴)。
常见遮蔽场景及示例
1. 方法参数遮蔽成员变量
立即学习“Java免费学习笔记(深入)”;
这是最典型的遮蔽情形。当方法参数名与类的成员变量名相同时,参数会遮蔽该成员变量:
public class Person {
private String name = "Alice";
public void setName(String name) { // 参数 name 遮蔽了成员变量 name
name = name; // 错误:赋值的是参数自身,成员变量未被修改
}
public void setNameCorrect(String name) {
this.name = name; // 使用 this 明确访问成员变量
}
}
2. 局部变量遮蔽成员变量
在方法内部声明同名局部变量,也会遮蔽成员变量:
public void printInfo() {
String name = "Bob"; // 局部变量遮蔽成员变量 name
System.out.println(name); // 输出 "Bob",不是成员变量的 "Alice"
System.out.println(this.name); // 需用 this 访问原始成员变量
}
3. 内部类中遮蔽外部类字段
内部类可定义与外部类同名字段,此时内部类字段遮蔽外部类字段:
public class Outer {
String data = "outer";
class Inner {
String data = "inner"; // 遮蔽 Outer 的 data
void show() {
System.out.println(data); // 输出 "inner"
System.out.println(Outer.this.data); // 输出 "outer"
}
}
}
如何避免或应对遮蔽问题
遮蔽本身不是语法错误,但容易引发逻辑错误或理解困难。建议采取以下做法:
- 命名时保持区分度:例如成员变量加
m前缀(mName)、下划线(_name)或使用my前缀,参数名用更具体的名字(如newName、inputName) - 善用
this关键字访问被遮蔽的实例变量,用ClassName.this访问外层类变量 - 启用 IDE 警告:IntelliJ 和 Eclipse 都支持对参数/局部变量遮蔽字段发出提示,可设为警告甚至报错
- 代码审查时留意同名现象,尤其在 setter、构造器和重载方法中
遮蔽与隐藏(hiding)、重写(overriding)的区别
三者常被混淆,关键区别如下:
- 遮蔽(Shadowing):发生在同一类不同作用域之间(如参数 vs 字段),仅影响编译期名称解析,适用于变量和类型(如局部类遮蔽外层类)
- 隐藏(Hiding):发生在继承关系中,子类的静态方法或静态字段与父类同名,会隐藏父类对应成员;调用取决于引用类型,而非实际对象类型
- 重写(Overriding):仅适用于非静态、非 private 的实例方法,子类提供新实现;调用取决于实际对象类型,体现运行时多态


















