多态是“用接口说话,让实现干活”的设计方式:编译时检查父类契约,运行时根据实际对象调用子类重写方法;需满足继承关系、方法重写、父类引用指向子类实例三个条件。

这其实是一种“用接口说话,让实现干活”的设计方式。你声明的是父类类型,但背后跑的是子类逻辑——编译时认类型,运行时看对象。
它不是类型转换,而是分工协作
Java 在编译阶段只检查你写的代码是否符合父类定义的契约:有没有这个方法?参数对不对?返回值是否合法?它不关心你背后 new 的是哪个子类。到了运行时,JVM 才根据实际对象类型,查虚方法表(vtable),跳转到子类重写后的方法执行。
- 编译期看左边:Animal a = new Dog(); → 编译器只允许调 a.eat()、a.sleep() 这些 Animal 类里声明过的方法
- 运行期看右边:如果 Dog 重写了 eat(),那 a.eat() 实际执行的就是 Dog.eat()
- 字段访问不走这套规则:a.name 取的是 Animal 类里的 name 值,哪怕 Dog 也定义了同名字段,也不会被访问到
它要能跑起来,必须满足三个条件
缺一不可,否则多态不会生效,甚至编译失败:
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
- 有继承或实现关系(比如 Dog extends Animal 或 ArrayList implements List)
- 子类重写了父类的非 private、非 static、非 final 方法
- 声明为父类类型,但用子类构造器创建实例(Animal a = new Dog();)
为什么不能直接调子类特有方法?
因为父类引用是一扇“受限的门”:它只暴露父类定义的能力。Dog 有 bark(),但 Animal 没声明,编译器就认为“所有 Animal 都不一定能 bark”,所以 a.bark() 直接报错。
立即学习“Java免费学习笔记(深入)”;
- 想用 bark()?得先确认身份:if (a instanceof Dog) { ((Dog) a).bark(); }
- 强行转型不加判断,运行时会抛 ClassCastException
- 这不是限制,而是保护——确保调用安全,不依赖具体实现细节
它真正解决的是工程问题
不是为了写得炫,而是让代码扛得住变化:
- 方法参数用 Animal,以后加 Sheep、Duck 都不用改 feed(Animal pet) 这一行
- List
animals = Arrays.asList(new Dog(), new Cat()); → 统一 animals.forEach(Animal::sound) - Payment pay = new WechatPay(); 换成 Alipay,只改这一行,业务层完全无感

















