重载是编译时静态绑定,依据声明类型和参数类型选择方法;重写是运行时动态绑定,依据对象实际类型调用子类实现。

关键不在方法名是否相同,而在于绑定发生的时间和依据:重载由编译器在编译时根据参数类型静态决定;重写由 JVM 在运行时根据对象实际类型动态分派。
看发生位置和前提条件
重载一定发生在同一个类内部,不依赖继承关系。只要参数列表(类型、个数、顺序)不同,就构成重载,哪怕只是 print(int) 和 print(Integer) —— 编译器会把它们当作两个完全独立的方法处理。
重写必须发生在父子类之间,且要求子类方法与父类非 private、非 static、非 final 的实例方法保持完全一致的签名(方法名 + 参数列表),返回类型允许协变(如父类返回 Animal,子类可返回 Dog)。
- 同一类里出现多个同名方法 → 一定是重载
- 子类中定义了一个和父类方法名、参数一模一样的方法 → 先检查父类方法是否可被重写(不是 private/static/final),再确认是否真被调用
- 没继承关系却有同名方法 → 不是重写,只是巧合重名
看调用时依据的是什么类型
重载选方法,看的是变量的**声明类型**和实参的**编译期类型**。比如:
Animal a = new Dog();feed(a); // 即使 a 实际是 Dog,也只看 a 声明为 Animal,走 feed(Animal) 版本
重写执行哪个实现,看的是对象的**实际运行时类型**。还是上面的例子:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 调用语句左边是父类引用,右边是子类 new 出来的对象 → 这是在测试运行时多态,重点观察是否触发重写
- 传入的参数是泛型或包装类,注意自动拆/装箱可能干扰重载匹配(如
add(int)和add(Integer)可能产生歧义) - 静态方法、private 方法、final 方法,无论怎么“同名”,都只能被隐藏或重载,无法被重写
看字节码指令和编译结果
编译后,重载方法调用对应的是 invokestatic 或 invokespecial 指令,目标在编译期就固化,运行时不会改变。
重写方法调用使用的是 invokevirtual 指令,JVM 在运行时查虚方法表(vtable)跳转,真正执行谁的代码,取决于堆中对象的真实 class。
- 删掉某个子类,代码仍能编译通过 → 说明是运行时行为(重写)
- 删掉某个重载方法,调用处立刻编译报错“找不到匹配方法” → 说明是编译时行为(重载)
- 加
@Override注解后编译失败 → 很可能是签名不一致、父类方法不可见,或根本不是重写场景
别混淆字段访问和方法调用
字段(成员变量)没有多态性。即使父类和子类都有同名字段,访问时永远按引用的声明类型来取值:
Animal a = new Dog();System.out.println(a.type); // 输出 Animal.type,不是 Dog.type
只有方法调用才触发动态绑定。这也是为什么多态必须靠方法,而不是靠字段来体现。
- 想让属性也具备多态行为?封装成 getter 方法,然后重写该方法
- 接口实现(
Shape s = new Circle())和抽象类子类化,底层机制和重写一致,都走invokeinterface或invokevirtual - 不要试图用重载模拟多态逻辑——它做不到运行时切换,只是编译期的一次性选择
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










