静态方法调用在编译期绑定,依据引用声明类型(如parent)执行对应类的方法;实例方法调用在运行期绑定,依据对象实际类型(如child)通过虚方法表动态分派。

调用时机决定行为逻辑
静态方法隐藏发生在编译期,JVM 根据变量的声明类型(左边类型)直接确定调用哪个类的方法。比如 Parent p = new Child(); p.staticMethod(); 会执行 Parent.staticMethod(),哪怕实际对象是 Child 类型——因为字节码里已写死目标类,用的是 invokestatic 指令。
实例方法重写发生在运行期,JVM 查虚方法表(vtable),根据对象的实际类型(右边类型)决定调用版本。p.instanceMethod() 此时执行的是 Child.instanceMethod(),依赖 invokevirtual 指令和动态分派机制。
@Override 注解是关键识别信号
给子类静态方法加 @Override 会编译失败,错误提示明确:“method does not override or implement a method from a supertype”。这说明 Java 语言层面拒绝承认这是重写行为。
而实例方法加上该注解,编译器会严格校验:签名一致、可访问、非 private、返回类型兼容、异常范围不扩大等。通过即代表满足重写契约。
- 静态方法无法被 @Override 标记 → 不是重写,只是同名新定义
- 实例方法能通过 @Override 校验 → 是受 JVM 多态机制支持的真正重写
设计意图完全不同
静态方法本质是工具函数,强调稳定性与可预测性。比如 Math.abs() 或 Objects.requireNonNull(),绝不应因继承关系改变行为。隐藏机制允许子类提供自己的工具实现,但不破坏父类原有语义。
实例方法代表对象的行为契约,是面向对象建模的核心。重写让子类能定制化实现,同时保持接口统一,支撑多态、开闭原则等关键设计思想。
- 隐藏:保留父类静态方法可用性,子类方法独立存在,互不影响
- 重写:子类替换父类行为,父类方法仍可通过 super 访问,形成行为扩展链
多态是否生效是根本分水岭
只有实例方法参与多态。所谓“父类引用指向子类对象”这一经典多态场景,对静态方法完全无效。它不查运行时类型,也不进虚方法表,因此没有动态绑定能力。
成员变量也遵循类似规则:同名变量是隐藏,访问同样取决于声明类型;而只有实例方法才能真正体现“一个接口、多种实现”的多态本质。
- 静态方法 + 变量 → 编译时绑定,看“怎么声明的”
- 实例方法 → 运行时绑定,看“实际是什么”
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











