java多态中编译时检查引用类型是否具备方法签名及访问权限,运行时根据实际对象类型动态绑定非static、非private、非final的实例方法;字段和静态方法不参与多态,转型才能访问子类特有成员。

Java 中多态的“编译时检查”和“运行时表现”,本质是两套独立又协同的机制:编译器管“能不能写、能不能过”,JVM 管“到底执行谁的代码”。关键不在语法是否漂亮,而在调用时行为是否可预期。
编译时只看引用类型(左边)
编译阶段不关心对象实际是谁,只认变量声明的类型。它做三件事:
- 检查该类型中是否存在被调用的方法签名(名称 + 参数类型);
- 验证访问权限(如 private 方法不可见);
- 若找不到匹配方法,直接报错,编译失败。
例如:Animal a = new Dog(); a.eat(); 编译器只查 Animal 类有没有 eat() 方法。哪怕 Dog 重写了,只要 Animal 没定义,就通不过编译。
运行时才看实际对象(右边)
程序跑起来后,JVM 根据 new 出来的真正类型决定执行逻辑:
- 若该类型重写了方法,就调用子类版本;
- 若没重写,沿继承链向上查找,直到找到第一个实现;
- 这个过程靠虚方法表(VMT)加速,属于动态绑定。
比如 a.eat() 在运行时发现 a 实际指向 Dog 实例,且 Dog 重写了 eat(),那就执行 Dog.eat(),不是 Animal.eat()。
字段和静态方法不参与多态
多态只对**非 static、非 private、非 final 的实例方法**生效:
- 访问字段时,始终按引用类型(左边)取值,不会动态切换;
-
static方法调用也看左边,因为属于类而非对象; -
private和final方法无法被重写,编译期就绑定了实现。
所以 Animal a = new Dog(); System.out.println(a.name); 输出的是 Animal 类里的 name 值,哪怕 Dog 自己定义了同名字段。
转型才能访问子类特有成员
父类引用不能直接调用子类新增的方法或字段:
- 想用
Dog特有的bark(),必须先转型:((Dog) a).bark(); - 但强制转型有风险,建议先用
instanceof判断:if (a instanceof Dog) { ((Dog) a).bark(); }
否则可能抛出 ClassCastException。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











