重载由编译器在编译期根据参数静态类型决定,重写由jvm在运行时根据对象实际类型通过虚方法表动态分派;重载不看对象实际类,重写不看引用声明类型;二者共存时先重载后重写。

区分重写与重载,关键看方法调用的决策时机:重载由编译器在编译期决定,重写由 JVM 在运行时决定。
重载是编译期静态分派
编译器仅根据变量的声明类型和实参的静态类型(即字面量或表达式的编译时类型)选择方法。它不关心对象实际是什么类,只查当前类的符号表,匹配参数个数、类型、顺序是否唯一可解。
- 例如:
print("abc")调用print(String),print(new Object())调用print(Object)——编译器已锁定目标方法 - 返回值类型不参与重载判断;仅返回值不同会报错:
method() is already defined - 自动装箱、泛型擦除可能引发歧义,如
handle(int)和handle(Integer)共存时,handle(5)一定走int版本,而handle(i)(i是Integer)才走包装类版本
重写是运行时动态分派
JVM 在执行 invokevirtual 指令时,根据对象的实际运行时类型(而非引用类型),查该类的虚方法表(vtable),找到最终要执行的方法实现。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 例如:
Animal a = new Dog(); a.speak();调用的是Dog.speak(),哪怕a声明为Animal - static、private、final 方法不进虚方法表,无法被重写;它们的调用在编译期就绑定,与对象实际类型无关
- @Override 注解只对重写有效,加在重载方法上会编译失败,这是最直接的语法提示
二者共存时的执行顺序
先重载,后重写。一个调用语句要先确定“调哪个签名”,再确定“该签名下执行谁的实现”。
- 比如父类有
void run(Object),子类重载了void run(String)并重写了void run(Object) - 那么
animal.run("hi")先通过重载选中String版本(若 animal 是子类实例,则执行子类的run(String));animal.run(new Object())则走重写的Object版本
常见混淆点的底层原因
很多误判源于没分清“看谁的类型”:重载看引用类型和参数字面量,重写看 new 出来的那个 class 对象。
- 构造方法只能重载,不能重写——因为构造方法不属于继承体系,没有父类构造方法可供覆盖
- 基本类型与包装类混用重载,容易让开发者误以为是重写,其实只是新增了一个同名方法,破坏了多态预期
- 泛型方法擦除后签名相同(如
list(List<string>)</string>和list(List<integer>)</integer>),编译直接拒绝,因为重载要求参数列表必须不同
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










