今天开发过程中, 有遇到一个场景, 创建了 Http 工具类, 方法签名如下
public void foo(String url, Object o) {
System.out.println("foo(String str, Object o) 被调用...");
}
public void foo(String url, Map<String, Object> map) {
System.out.println("foo(String str, Map<String, Object> map) 被调用...");
}
public void foo(String url, HashMap<String, Object> map) {
System.out.println("foo(String str, HashMap<String, Object> map) 被调用...");
}
于是好奇, 第二个参数传入 Map 对象, 那么真正哪个重载方法会被调用, 运行 test 方法
/**
* 重载方法形参涉及父子类时
* 例如这里 Object > Map > HashMap
* 重载方法会优先选择最具体的子类
* 如果数据类型不匹配, 再向上查找
* 都不满足, 则编译报错
*/
@Test
public void testOveride() {
String str = "test";
// 会选择 Object 方法
foo(str, "你好鸭");
Map<String, Object> map = new HashMap<>();
map.put("key", 123);
// 会选择 Map 方法
foo(str, map);
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("key", 123);
// 会选择 HashMap 方法
foo(str, hashMap);
Object obj = new HashMap<>();
// 按照左侧参数声明类型调用, 而不是右侧的实现类类型
// 会选择 Object 方法
foo(str, obj);
}
查看字节码. 发现重载方法是在编译期确定的.
下图是最后一个方法的字节码, 可以看到调用的是 形参为 Object
的重载方法
由此验证后, 得到结论
重载方法是在编译期确定的
重载方法的形参涉及父子类时, 总是优先选择最具体形参的重载方法
并且需要注意的是, 是按照传入参数声明的类型去比较, 而不是 new
的类型.
即如果声明 Object map = new HashMap();
那么会选择 Object
的重载方法, 而不是 HashMap
的那个重载方法