Java多态依赖JVM运行时类型识别与动态方法分派:对象关联唯一Class对象,getClass()返回实际类型;方法调用通过虚方法表动态绑定子类实现;字段访问无多态性,由编译时类型决定;向下转型须用instanceof或isInstance()保障安全。

Java 中多态的运行时类型识别与处理,本质依赖于 JVM 在运行期对对象实际类型的追踪和方法调用的动态分派机制,不是靠开发者手动判断,而是由语言底层自动保障。
运行时类型识别靠 Class 对象
每个 Java 对象在创建时,JVM 都会为其关联一个唯一的 Class 对象,它代表该实例“真正属于哪个类”。这个关联不会因引用类型变化而改变。
-
getClass() 返回真实类型:无论变量声明为 Animal、Object 还是 Serializable,调用
a.getClass()永远返回运行时实际类(如class Dog) - 向上转型不改变 Class:即使写
Animal a = new Dog(),a.getClass()仍是Dog.class - Class 对象可用来做类型检查或反射操作,例如:
if (a.getClass() == Dog.class) { ... }(但通常应优先用instanceof)
方法调用靠动态绑定(Virtual Method Invocation)
当通过父类引用调用一个被重写的方法时,JVM 不看变量声明类型,而是查对象的 Class 对象里的虚方法表(vtable),找到对应子类实现的方法入口并执行。
- 触发条件:必须是非 private、非 static、非 final 的实例方法,且已被子类重写
- 编译时只校验方法是否存在(按声明类型),运行时才决定调哪个版本
- 例如:
Animal a = new Dog(); a.speak();→ JVM 查Dog.class的 vtable,调用Dog.speak()
字段访问不具多态性,需特别注意
字段(成员变量)没有动态绑定机制。访问哪个字段,完全由引用的编译时类型决定,和对象实际类型无关。
立即学习“Java免费学习笔记(深入)”;
- 父类和子类定义同名字段时,它们是独立存储的
-
Base b = new Sub(); System.out.println(b.field);→ 输出的是Base.field的值 - 若需按实际类型取值,得显式转型:
((Sub)b).field,或改用 getter 方法(getter 可被重写,具有多态性)
安全向下转型需配合 instanceof 或 Class.isInstance()
当需要调用子类特有方法(如 Dog.guardHouse())时,必须先确认对象确实是该子类实例,否则会抛 ClassCastException。
- 推荐用
if (a instanceof Dog) { ((Dog)a).guardHouse(); } - 也可用
Dog.class.isInstance(a),效果等价,适合泛型或反射场景 - 避免无条件强转,那是运行时隐患


















