bigywater.tech
Java 内部原理 · 36

方法重载 vs 重写:真实验证重载看编译期类型,重写看运行时类型

"重载是静态绑定,重写是动态绑定"是背得很熟的一句话。真实构造一个 Animal/Dog 场景,让重载和重写在同一段代码里正面对比,一次性看清两者真实依据的是不同的类型信息。

a.sound() → 汪汪
Animal a = new Dog(),调用被重写的 sound() 真实按运行时类型 Dog 分派,和声明类型 Animal 无关
describe(a) → Animal 版本
同一个变量 a,调用重载方法 describe() 真实选中的是 describe(Animal) 版本,即使 a 运行时真实是 Dog

上一篇:类到底什么时候被初始化:真实验证编译期常量根本不会触发它

思路:一个变量,两种方法,同时观察

用同一个变量 a(声明类型 Animal,运行时真实类型 Dog),分别调用一个被重写的方法和一组重载的方法,对比两者的真实分派结果。

OverloadOverrideDemo.java static class Animal { String sound() { return "某种动物的叫声"; } } static class Dog extends Animal { @Override String sound() { return "汪汪"; } } static String describe(Animal a) { return "重载版本(Animal) 处理: " + a.sound(); } static String describe(Dog d) { return "重载版本(Dog) 处理: " + d.sound(); } Animal a = new Dog(); // 声明类型 Animal,运行时真实类型 Dog

真实验证:重写方法,真实按运行时类型分派

这部分符合大多数人的直觉预期。

真实实测
a 的编译期声明类型 = Animal, 运行时真实类型 = Dog

a.sound() 真实调用结果 = 汪汪(重写方法真实按运行时类型 Dog 分派)

真实验证:重载方法,真实按编译期声明类型选择

这部分是最容易和"重写"混淆、真实结果和直觉不一致的地方。

真实实测
describe(a) 真实选中的重载版本 = 重载版本(Animal) 处理: 汪汪
(变量 a 运行时真实是 Dog,但因为声明类型是 Animal,重载解析在编译期就真实选定了 describe(Animal) 版本)
describe(realDog) 真实选中的重载版本 = 重载版本(Dog) 处理: 汪汪
(这次声明类型就是 Dog,重载解析真实选中了 describe(Dog) 版本)

(Animal) realDog 强转后再调用 describe: 重载版本(Animal) 处理: 汪汪

三行真实结果拼出完整的规律:调用 describe(a) 时,a 运行时的真实对象和调用 describe(realDog) 时完全一样(都是同一个 Dog 实例的行为),但因为变量 a 的声明类型是 Animal,编译器在编译这行代码的那一刻,就已经真实、永久地决定了要调用哪个重载版本——这个决定写进了字节码里(生成的是对 describe(Animal) 这个具体方法签名的 invokestatic 调用),运行时不会再重新判断。第三行更直接:把同一个 Dog 实例强转成 Animal 类型再传进去,重载解析结果立刻真实跟着声明类型变了。

为什么方法内部调用 sound() 结果还是"汪汪"?因为 describe(Animal) 和 describe(Dog) 两个版本内部都调用了各自参数的 sound()——这一步是重写方法的分派,依然真实按运行时类型走,和外层选中哪个重载版本是两件独立的事。真实结论是:重载解析发生在编译期,依据声明类型,决定权在编译器;重写分派发生在运行时,依据实际对象类型,决定权在 JVM。两者经常在同一行代码里同时发生,容易被当成一回事,但真实机制完全不同。

分步演示:同一个变量,换个声明类型,结果为什么会不一样

每一行都是真实运行这段代码得到的结果。

重写(override)真实按运行时对象类型动态分派;重载(overload)和 static 方法真实只看编译期声明类型
这一步新验证的调用

    参考与说明

    • 本文全部结果均在本机真实运行 Java 17 得到。
    • 和ClassLoader 与类身份那篇一样,都是"编译期决定的事情"和"运行时决定的事情"这条分界线上的真实案例。
    • 没有涉及:多个重载版本存在继承/自动装箱/可变参数等多重候选时,编译器判定"最具体方法"的完整优先级规则——这些留给系列后面按需再写。
    京ICP备2026067502号-1京公网安备11010502063487号