Java中子类不能覆盖父类属性,只能隐藏——即同名字段在父子类中独立存在;隐藏需满足同名同类型且父类字段非private;字段访问为静态绑定,无多态性,应优先使用private字段+getter/setter避免混淆。

Java 中子类不能真正“覆盖”父类属性,只能“隐藏”——这是语言规范明确规定的机制,不是 bug,而是设计使然。隐藏效果的本质,是子类和父类各自保留一份同名字段,它们在内存中独立存在、互不影响。
隐藏发生的前提条件
只有当子类定义了与父类**同名、同类型(或可兼容)的字段**,且该字段在父类中是可访问的(即非 private),才会触发隐藏。例如:
- 父类有 protected int count;
- 子类也声明 int count;(默认包级)或 private int count;
- 此时子类的 count 就会隐藏父类的 count
隐藏的具体表现
同一个对象,通过不同引用类型访问同名字段,结果可能不同:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- this.count → 访问子类自己的字段(若已声明)
- super.count → 明确访问父类被隐藏的那个字段
- 将子类对象赋给父类引用:Parent p = new Child();,再调用 p.count → 实际访问的是父类字段(因为字段访问由编译时类型决定)
为什么叫“隐藏”而不是“覆盖”
关键区别在于绑定时机和多态行为:
立即学习“Java免费学习笔记(深入)”;
- 字段访问是静态绑定:编译器根据变量声明类型(如 Parent 或 Child)决定读哪个字段,运行时不会动态切换
- 方法调用是动态绑定:即使 Parent p = new Child(),调用 p.show() 仍执行子类重写后的方法
- 所以字段不能体现多态;隐藏是编译期现象,覆盖是运行期现象
如何避免隐藏带来的混淆
实际开发中应尽量规避同名字段:
- 优先使用 private 字段 + public/protected getter/setter,让子类通过方法间接操作父类状态
- 子类如需扩展状态,改用不同名称(如父类 id,子类用 serialId)
- 若必须同名,务必用 super.xxx 显式区分,尤其在构造器或初始化逻辑中

















