重载是编译期静态分派,依据参数类型和数量在编译时通过静态类型和方法签名确定调用版本;重写是运行期动态分派,依据对象实际类型通过虚方法表查找子类实现。

Java中方法重载(Overload)和重写(Override)是面试必考基础点,但很多人只背结论、不究原理,一问“为什么编译期能识别重载”或“重写为何不能扩大访问权限”,就卡壳。关键不在记规则,而在理解字节码层面的分派机制和JVM方法解析逻辑。
重载:编译期静态分派,看的是参数类型和数量
重载发生在同一个类中,方法名相同但参数列表不同(类型、个数、顺序)。JVM在编译阶段就通过静态类型和方法签名(name + descriptor)确定调用哪个版本,生成的字节码指令是invokestatic或invokevirtual,但目标方法符号引用已在class文件里固定。
- 返回值类型、异常声明、访问修饰符不同,不算重载
- 自动类型转换(如int→long)和装箱拆箱(int↔Integer)会影响重载解析,优先匹配最精确的类型
- 泛型擦除后,
void foo(List<string>)</string>和void foo(List<integer>)</integer>实际都是foo(List),无法构成重载
重写:运行期动态分派,靠的是实际类型+虚方法表
重写发生在父子类之间,要求方法名、参数列表、返回类型(协变返回除外)一致,且子类访问权限不能更严格。JVM在运行时根据对象的实际类型(而非引用类型),通过虚方法表(vtable)查找并跳转到子类的具体实现。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- private、static、final 方法不能被重写(它们不进vtable;static走静态绑定;final被JVM标记为不可覆盖)
- 构造器、成员变量、静态字段都不参与重写——只有实例方法才进vtable
- 协变返回(如父类返回Object,子类返回String)是编译器语法糖,字节码中仍保持桥接方法(bridge method)保证多态正确性
常见陷阱题直击底层
面试官爱挖的点,往往藏在字节码和JVM规范细节里:
- “子类重写父类方法,抛出更多异常会怎样?” → 编译报错。因为重写方法的异常声明必须是父类方法异常的子集(或不抛),这是编译期强制检查的契约,保障多态调用的安全性
- “重载和重写能否共存?” → 可以。例如子类既重写了父类方法,又在同一类中重载了同名方法。两者作用域不同(重载在类内,重写跨类),互不影响
- “接口默认方法能否被重写?能否被重载?” → 可被重写(需public),也可被重载(只要参数不同);但接口里不能定义重载的多个默认方法同名——因为接口不支持方法体重复声明
一句话总结本质
重载是编译器的事:靠参数签名静态绑定;重写是JVM的事:靠对象实际类型+虚方法表动态绑定。不理解分派时机(compile-time vs run-time)和绑定依据(静态类型 vs 实际类型),所有规则都是空中楼阁。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










