子类不能覆盖静态变量,只能隐藏它;静态变量属于类本身而非继承体系,子类声明同名static变量会创建独立副本,编译期绑定引用类型而非运行时对象类型。

子类不能覆盖静态变量,但可以“隐藏”它——这是 Java 中一个容易误解的关键点。
静态变量不属于继承体系,而是属于类本身
static 修饰的变量是类变量,随类加载而存在,内存中只有一份,与对象无关。它不参与继承链的传递,因此严格来说,子类没有继承父类的静态变量,只是在未声明同名静态变量时,能通过类名或子类实例间接访问父类的那份变量。
- 若子类定义了与父类同名的 static 变量(如
public static int num = 2;),这并非覆盖,而是变量隐藏(hiding):子类有自己的存储空间,父类和子类的num是两个独立变量 - 通过
ParentClass.num访问的是父类的值;ChildClass.num访问的是子类的值;即使用new ChildClass().num,实际读取的仍是子类声明的静态变量(若存在)或父类的(若子类未声明) - 这种隐藏不触发多态,也不受访问权限影响(private 静态变量无法被子类直接访问,自然也无法隐藏)
为什么不能叫“覆盖”?
覆盖(override)是针对实例方法的运行时多态行为:子类重写父类非 private、非 static 的方法,调用取决于实际对象类型。而静态变量和静态方法的绑定发生在编译期,依据的是引用类型或类名,与对象实际类型无关。
-
Parent p = new Child(); p.staticVar→ 读取的是Parent.staticVar -
Child c = new Child(); c.staticVar→ 若Child声明了同名 static 变量,则读取Child.staticVar - 这和
p.instanceMethod()会调用Child版本形成鲜明对比
实际开发中的建议
为避免混淆和维护风险,应主动规避静态变量隐藏:
立即学习“Java免费学习笔记(深入)”;
- 尽量使用
final static定义常量,并采用全大写命名(如MAX_RETRY),明确其不可变性 - 避免在子类中重新声明同名 static 变量;如需不同值,改用独立名称(如
PARENT_TIMEOUT/CHILD_TIMEOUT) - 若逻辑上确需“子类专属配置”,优先考虑依赖注入或工厂模式,而非静态变量隐藏
本质上,static 和继承是两条平行线:一个面向类,一个面向类型层级。理解这点,就能避开绝大多数因“以为能覆盖”引发的 bug。


















