Java多态核心是“父类引用指向子类对象”,依赖继承、方法重写和向上转型,编译看父类、运行看子类,实现统一处理不同子类,但父类引用无法访问子类特有成员。

Java 中的多态,核心就体现在“父类引用指向子类对象”这一写法上。它不是语法糖,而是基于继承和方法重写的运行时行为——编译看左边(父类),运行看右边(子类)。
一、基本写法:声明父类类型,实际创建子类实例
这是实现多态的第一步,也是最直观的形式:
- 声明一个父类(或接口)类型的变量;
- 用 new 子类() 初始化它;
- 调用的方法,如果子类重写了,就会执行子类版本。
例如:
Animal a = new Dog(); // 父类引用 a 指向子类 Dog 实例 a.sound(); // 输出 "汪汪!",不是 Animal 的默认实现
这里 a 编译时被当作 Animal 类型,所以只能调用 Animal 中声明过的方法;但运行时 JVM 发现它实际是 Dog,且 sound() 被重写,于是动态绑定到 Dog.sound()。
立即学习“Java免费学习笔记(深入)”;
二、关键前提:继承 + 方法重写 + 向上转型
这个机制能生效,必须同时满足三个条件:
- 有继承关系:子类 extends 父类,或实现同一接口;
- 有可重写的方法:父类中是非 private、非 static、非 final 的实例方法;
- 发生了向上转型(upcasting):把子类对象赋给父类引用,这是自动发生的,无需强制类型转换。
注意:Dog d = (Dog) new Animal(); 是向下转型,会抛 ClassCastException,因为父类对象无法变成子类——多态不支持反向。
三、真正体现多态价值的地方:统一处理不同子类
多态的意义不在单个赋值,而在于让方法参数、集合、返回值等能“无视具体类型”,只依赖抽象定义:
- 方法接收父类参数:
void feed(Animal a) { a.eat(); },传new Dog()或new Cat()都可以; - 集合存多种子类:
List<Animal> pets = Arrays.asList(new Dog(), new Cat(), new Bird());,遍历时各调各的sound(); - 工厂方法返回父类类型:
Animal create(String type) { return "dog".equals(type) ? new Dog() : new Cat(); },调用方不用关心构造细节。
四、容易忽略的限制:父类引用不能访问子类特有成员
虽然对象是子类的,但通过父类引用只能看到父类声明的部分:
- 不能调用子类新增的方法(如
Dog.fetch()),编译报错; - 不能访问子类新增的字段(如
Dog.breed),同样编译不通过; - 若真需要子类专属能力,得先判断再向下转型:
if (a instanceof Dog) { ((Dog)a).fetch(); },但这会削弱多态性,应谨慎使用。
本质上,父类引用只是“戴上了一副父类的眼镜”来看这个对象——看到的是父类定义的公共契约,而不是对象全部能力。


















