今天在论坛闲逛的时候发现了一个很有趣的题目:
package test; public class Test { public void myMethod(String str) { System.err.println("string"); } public void myMethod(Object obj) { System.err.println("object"); } public static void main(String[] args) { Test t = new Test(); t.myMethod(null); } }
咋一看,传递给方法的参数是一个空的对象引用,因此,初看起来,该程序好像应该调用参数类型为Object 的重载版本,
并且将打印出Object。另一方面,String也是引用类型,因此null 也可以应用于类型为String的重载版本。
你由此可能会得出结论:这个调用是模棱两可的,该程序应该不能编译。如果你试着去运行该程序,
就会发现这些直观感觉都是不对的:该程序打印的是String。
其实这个题不是很新鲜了,在《Java解惑》里面有一个类似的题目,不过那个题目是重载的构造器,不过他们的原理是一样的。
Java 的重载解析过程是以两阶段运行的。第一阶段选取所有可获得并且可应用的方法或构造器。第二阶段在第一阶段选取的方法或构造器中
选取最精确的一个。如果一个方法或构造器可以接受传递给另一个方法或构造器的任何参数,那么我们就说第一个方法比第二个方法缺乏精确性。
在我们的程序中,两个方法都是可获得并且可应用的。方法构造器myMethod(Object)可以接受任何传递给myMethod(String)的参数,
因此myMethod(Object)相对缺乏精确性。(每一个String都是一个Object,但是每一个Object 并不一定是一个String。)因此,
最精确的方法就是myMethod(String),这也就解释了为什么程序会产生这样的输出。如何想输出Object 你可以这样调用myMethod((Object)null).