多态依赖“编译看左,运行看右”原则:编译时检查引用类型是否有该方法,运行时根据实际对象类型调用重写方法;需满足继承关系、子类重写非私有非静态非final方法、向上转型三个前提;仅实例方法支持多态,字段和静态方法不具多态性。

多态依赖“编译看左,运行看右”原则
Java中方法调用的解析分两个阶段:编译时只检查引用变量的声明类型(左边),确保调用的方法在该类型中存在、签名合法;运行时才根据对象实际创建的类(右边)决定执行哪个具体实现。比如 Animal a = new Dog();,编译器只认 Animal 类里有没有 makeSound() 方法,而 JVM 在执行 a.makeSound() 时,会查 Dog 实例的真实类型,并调用其重写版本。
必须满足三个前提条件
缺一不可:
- 存在继承关系(或接口实现),形成“is-a”结构,如 Dog extends Animal 或 Dog implements Pet
- 子类重写了父类的非私有、非静态、非 final 方法,且方法签名(名称 + 参数列表)完全一致
- 发生向上转型:用父类/接口类型声明引用,但指向子类/实现类实例,例如 Animal a = new Dog(); 或 Pet p = new Cat();
运行时靠虚方法表(vtable)动态绑定
JVM 为每个类维护一张虚方法表,记录所有可被重写的方法及其实际入口地址。当调用一个被重写的方法时:
- JVM 先通过对象头定位其真实类的 vtable
- 再根据方法签名查表,直接跳转到子类方法的字节码位置
- 这个过程叫“动态绑定”,它不依赖编译期信息,也不走反射,开销小且高效
注意:static、private、final 方法不会进 vtable,所以无法参与运行时多态。
立即学习“Java免费学习笔记(深入)”;
属性和静态方法不具多态性
多态只适用于**实例方法**的调用:
- 访问字段(如 a.name)永远由引用类型(编译时类型)决定,子类同名字段不会覆盖父类字段,只是隐藏
- 静态方法(static)绑定在类上,调用取决于引用的声明类型,不是对象实际类型
- 构造方法、初始化块、成员内部类等也不参与多态机制










