父类引用指向子类对象体现Java多态机制,即“编译看类型,运行看实例”,仅实例方法参与动态绑定;字段、static、private、final方法均不支持多态。

父类引用指向子类对象,本质是“编译看类型,运行看实例”
这不是类型转换,也不是语法糖,而是 Java 多态的底层约定:用 Animal a = new Dog(); 这样的写法时,a 的编译期类型是 Animal,但 JVM 在运行时会查这个对象真正的 class 是 Dog。所以调用 a.sound() 时,执行的是 Dog.sound() ——前提是该方法被重写了。
关键点在于:只有**实例方法**参与这个机制;static 方法、成员变量、private 或 final 方法都不行。比如 a.name 永远取 Animal.name,哪怕 Dog 里也定义了同名字段。
为什么不能直接调用子类独有方法?怎么安全调用?
因为编译器只认引用声明的类型。写 a.bark() 会直接报错:cannot resolve method 'bark()' in 'Animal' ——它根本不管右边是不是 Dog。
要调用子类特有行为,必须先确认再转型:
立即学习“Java免费学习笔记(深入)”;
- 用
instanceof判断:if (a instanceof Dog) { ((Dog) a).bark(); } - Java 14+ 推荐模式匹配写法:
if (a instanceof Dog d) { d.bark(); }(更简洁,且自动完成向下转型) - 千万别跳过判断直接强转:
(Dog) a可能抛ClassCastException
多态真正有用的地方:参数统一、集合泛型、框架扩展
不是为了炫技,而是解决实际问题。比如你写一个通用处理方法:
void feed(Animal animal) {
animal.eat();
}
传 new Dog() 或 new Cat() 都能进同一段代码,行为却不同。再比如集合:
Listanimals = Arrays.asList(new Dog(), new Cat(), new Bird());
遍历调用 sound(),每种动物各响各的——新增 Fish 类?只要继承 Animal 并重写方法,原有循环逻辑完全不用改。
最容易忽略的坑:字段不支持多态,静态方法也不走重写
新手常以为 “父类引用指向子类对象” 就等于“一切行为都按子类来”,但字段访问和静态方法恰恰相反:
-
Animal a = new Dog(); System.out.println(a.name);→ 输出Animal的值(字段看引用类型) -
a.print();(假设print()是static)→ 调用的是Animal.print(),不是Dog.print() - 虚方法表(vtable)只管实例方法,字段和静态方法压根不进这张表
所以别指望靠多态“覆盖”字段或静态工具方法——那是设计信号:该用抽象方法、getter 或策略模式了。










