为什么输出是这样的?

时间:2010-06-14 12:48:16

标签: java polymorphism scjp

class Another {
    public void method(Object o) {
        System.out.println("This is in method which takes object");
    }
    public void method(String s) {
        System.out.println("This is method which takes string");
    }
}

public class NewClass {
    public static void main(String args[]) {
        Another an = new Another();
        an.method(null);
    }
}

当我尝试执行此操作时,我得到了

  

这是采用字符串

的方法

作为输出。为什么不“这是采取对象的方法”?对象也可以为null,string也可以为null,为什么不调用第一个方法?

4 个答案:

答案 0 :(得分:25)

根据Java Language Specification,在这两种方法都可以处理提供的参数的重载方法的情况下,选择具有更具体参数的方法。由于StringObject更具体(String延伸Object),因此会选择并调用void method(String)

答案 1 :(得分:7)

这与JLS中指定的完全相同:

  

JLS 15.12.2.5 Choosing the Most Specific Method

     

如果多个成员方法都可访问并适用于方法调用,则必须选择一个为运行时方法调度提供描述符。 Java编程语言使用选择最具体方法的规则。

StringObject,但并非所有Object都是String。因此,String 更具体而不是Object,因此在上面的示例中选择String重载的原因。


值得注意的是这个确切的问题(实质上)出现在精彩的Java Puzzlers(强烈推荐)中,特别是 Puzzle 46:令人困惑的构造函数的案例< / em>的

  

Java的重载解析过程分两个阶段进行。第一阶段选择可访问和适用的所有方法或构造函数。第二阶段选择在第一阶段中选择的方法或构造函数的最具体的。如果一个方法或构造函数可以接受传递给另一个

的任何参数,那么它的特定性不如另一个      

理解这个难题的关键是哪个方法或构造函数最具体的测试不使用实际参数 :调用中出现的参数。它们仅用于确定适用的过载。一旦编译器确定哪些重载适用且可访问,它将仅使用形式参数选择最具体的重载:声明中出现的参数。


我将结束 Effective Java 2nd Edition 的引用,第41项:明智地使用重载

  

确定选择哪个重载的规则非常复杂。他们在语言规范中占用三十三个页面,很少有程序员理解他们的所有细微之处。

毋庸置疑,本书也是强烈推荐的

另见


关于显式转换

  

那么如何用Object参数调用null重载?

简单:将null投射到Object类型。有几个场景,这是有用/必要的,这是其中之一。

  

如果我有超载,例如Integer

,该怎么办?

然后方法调用不明确,并发生编译时错误。

  

JLS 15.12.2.5 Choosing the Most Specific Method

     

有可能没有最具体的方法,因为有两种或更多种方法是最具体的。在这种情况下[...有一些例外]我们说方法调用是不明确的,并且发生编译时错误。

要解决歧义,您可以再次将null(或其他表达式)转换为所需的重载类型。

另见

答案 2 :(得分:5)

在解决重载方法调用时,编译器总是会找到最窄的匹配。

顺便说一下,Java约定是为类使用大写名称,即Another

答案 3 :(得分:1)

我很确定在这样的情况下,使用Java 6(我认为Java 5会抛出编译器错误),它会选择最低级别的类来将null归于。 (因为String是一个对象,它在层次结构中较低)