java中static方法采用静态绑定,编译期即根据声明类型(类名或变量声明类型)锁定调用目标,生成invokestatic指令,不依赖对象实例、不查虚表、不支持多态,子类同名方法仅为隐藏而非重写。

Java编译器对 static 方法的处理,本质是“不看对象、只看类名”——调用目标在写完代码那一刻就已锁定,编译器直接生成确定指令,运行时完全不查、不判、不换。
静态绑定的核心判断依据:声明类型而非实际类型
编译器只认你代码里“点号左边”写的那个类名(或变量的声明类型),不管右边 new 出来的是谁。比如:
-
A a = new B(); a.m();→ 编译器看到a声明为A类型,就认定调用A.m() -
B b = new B(); b.m();→ 编译器看到b声明为B,就选B.m() -
A.m();或B.m();这种直接类名调用,更直白:类名写哪,就绑哪
字节码层面的证据:invokestatic 指令固化符号引用
javac 编译后,每个 static 方法调用都会变成一条 invokestatic 指令,其操作数指向常量池中一个**不可变的符号引用**(如 "LA;->m()V")。这个引用在 .class 文件生成时就写死了,JVM 运行时照单执行,不做任何类型检查或方法表查找。
- 没有虚方法表(vtable)参与
- 不依赖 this 或任何对象实例
- 即使传入 null 引用(如
((String)null).valueOf(123)),也不会触发空指针——因为 null 根本没被当作接收者使用
与重写(override)的根本区别:隐藏(hiding)不是多态
子类定义同签名 static 方法,不是重写,而是独立存在。调用结果只取决于你写的类名,而非运行时对象归属:
-
A.m()总执行 A 类里的版本 -
B.m()总执行 B 类里的版本 - 不存在 “父类引用指向子类实例,然后调用子类 static 方法” 这回事——这种理解本身违背 static 绑定逻辑
为什么只有这几类方法能静态绑定?
static、private、final、构造方法,共同特点是:语义上不允许被子类动态替换。编译器可凭语法和继承规则,在编译期 100% 推断出唯一可行目标:
- static 属于类,与实例无关
- private 不可继承,调用范围锁死在本类
- final 明确禁止覆盖,子类无法提供替代实现
- 构造方法不能被继承,每个 new 都对应明确的类字面量
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











