这是变量遮蔽现象:参数year与成员变量year同名导致赋值未修改成员变量;应使用this.year = year显式访问成员变量;遮蔽与方法覆盖本质不同,前者是变量作用域规则,后者是运行时多态机制。

为什么 year = year 赋值后对象字段还是 0?
这是最典型的遮蔽(hiding)现象:方法参数或局部变量与成员变量同名时,未加限定的赋值操作全部作用于局部变量,成员变量根本没被修改。
- Java 编译器在作用域内按“就近原则”解析变量名——先找局部变量,再找成员变量
-
year = year中左右两边都是参数year,等价于year = year(自赋值),对成员变量year零影响 - 运行结果为
0 0 0,正是因为成员变量始终用默认值(int类型默认是0)
怎么用 this 正确访问被遮蔽的成员变量?
当局部变量/参数和成员变量重名,必须显式用 this. 前缀才能访问当前对象的成员变量。
- 正确写法是:
this.year = year、this.month = month、this.day = day -
this指向正在执行该方法的对象实例,不是关键字也不是变量,不能赋值或重定义 - 静态方法中不能用
this—— 因为没有“当前实例”,此时若需访问静态成员变量,直接用类名或省略前缀即可
public void setDate(int year, int month, int day) {
this.year = year; // ✅ 修改成员变量
this.month = month;
this.day = day;
}
遮蔽和覆盖(overriding)是一回事吗?
完全不是。遮蔽(hiding)是变量层面的作用域规则;覆盖(overriding)是方法层面的多态机制,二者发生位置、触发条件、编译/运行时行为都不同。
- 遮蔽发生在**同一个类内**(局部变量 vs 成员变量)或**父子类之间**(子类定义了与父类同名的静态字段或常量),由编译器静态决定
- 覆盖只适用于**非静态、非私有、非 final 的实例方法**,且要求签名一致,由 JVM 运行时动态绑定
- 字段永远不覆盖——子类声明同名字段只是遮蔽父类字段,不会参与多态分派
开发中哪些命名习惯会放大遮蔽风险?
IDE 往往不报错,但逻辑错误极难察觉。遮蔽本身合法,但容易掩盖意图,尤其在 setter 或构造器中。
立即学习“Java免费学习笔记(深入)”;
- 避免参数名和成员变量名完全一致(如
String name参数配private String name字段) - 常见缓解方案:
name(字段) +newName(参数),或统一用this.name = name风格并开启 IDE 警告(如 IntelliJ 的 “Field can be assigned from parameter”) - 使用 Lombok 的
@Setter或记录类(record)可绕过手动 setter,自然规避该问题
this.,程序就静默地跑偏了。









