重载方法调用由编译时类型决定,与运行时对象实际类型无关;编译器依据实参表达式的静态类型匹配方法,遵循精确匹配→自动提升→装箱拆箱→可变参数的优先级顺序。

多态方法调用时的入参匹配,和“向上转型”本身无关,关键在于重载(overloading)解析发生在编译期,而这个过程只看引用变量的静态类型,不是运行时对象的真实类型。也就是说:参数怎么转型、转成什么,取决于你传进去的那个表达式的编译时类型,而不是它背后实际是哪个子类实例。
重载方法选择靠编译时类型,不是运行时对象
比如有 void show(Animal a) 和 void show(Dog d) 两个重载方法,你写 show(animalRef),编译器只看 animalRef 的声明类型(比如是 Animal),就直接选定 show(Animal),哪怕 animalRef 实际指向的是 Dog 实例。这和多态(override)完全不是一回事。
- 重载(overloading):同一个类里多个同名方法,参数列表不同;由编译器静态决定调用哪个,依据是实参表达式的编译时类型
- 重写(overriding):子类改写父类方法;由 JVM 运行时动态决定执行哪个版本,依据是被调用对象的实际类型
参数“向上转型”发生在传参前,影响重载匹配
当你把一个子类对象赋给父类引用,再把这个引用作为实参传入,这个父类引用就是“已转型”的状态。编译器看到的就是父类类型,所以只会去匹配接受该父类或其父类的重载方法。
-
Dog d = new Dog(); show(d);→ 编译器看到实参是Dog类型,优先选show(Dog) -
Animal a = d; show(a);→ 编译器看到实参是Animal类型,即使a指向Dog,也只会考虑show(Animal)或更宽泛的类型(如Object) - 没有
show(Animal),但有show(Object),那show(a)就会匹配到后者——因为Animal向上转型为Object是合法的自动转型
匹配顺序严格遵循“就近原则”
编译器对重载方法的查找不是模糊搜索,而是按明确优先级逐层尝试:
- 第一步:找参数类型完全一致的方法(精确匹配)
- 第二步:找不到,尝试基本类型自动提升(
int→long、byte→int等) - 第三步:再找不到,尝试装箱(
int→Integer)、拆箱(Integer→int) - 第四步:最后才考虑可变参数方法(
show(String...))
注意:这个顺序不会因为对象实际是子类就跳过父类匹配项。例如 show(Number) 和 show(Object) 都存在,传入 Integer 变量,编译器选 show(Number),因为 Integer 直接继承自 Number,比 Object 更“近”。
避免混淆:多态不参与重载决策
常有人误以为“既然 Animal a = new Dog() 调用 a.sound() 会执行 Dog.sound(),那传参时也应该按 Dog 来选重载方法”。这是典型混淆。前者是方法调用的动态绑定(override),后者是方法选择的静态解析(overload),两者机制完全独立。
- 写
a.sound():编译看Animal有没有sound()(有,编译通过),运行看a实际是Dog(执行Dog.sound()) - 写
show(a):编译直接根据a的声明类型Animal锁定重载目标,运行时不会重新判断
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











