13
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);
    }
}

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

这是采用字符串的方法

作为输出。为什么不“这是采用对象的方法”?对象也可以为空,字符串也可以为空,为什么不调用第一种方法呢?

4

4 回答 4

25

根据Java 语言规范,在两种方法都可以处理提供的参数的重载方法的情况下,选择具有更具体参数的方法。由于StringObject( Stringextends Object) 更具体,void method(String)因此被选择和调用。

于 2010-06-14T12:54:27.500 回答
7

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

JLS 15.12.2.5 选择最具体的方法

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

A Stringis-a Object,但并非所有Objectis-a String。因此,String比更具体Object,因此String在上面的示例中选择了重载。


值得注意的是,这个确切的问题(本质上)出现在精彩的Java Puzzlers(强烈推荐)中,特别是Puzzle 46: The Case of the Confusing Constructor

Java 的重载解决过程分两个阶段进行。第一阶段选择所有可访问和适用的方法或构造函数。第二阶段选择第一阶段选择的最具体的方法或构造函数。如果一个方法或构造函数可以接受传递给另一个的任何参数,则它的特定性低于另一个

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


我将引用Effective Java 2nd Edition第 41 条:明智地使用重载

确定选择哪种重载的规则非常复杂。它们在语言规范中占据了33页,很少有程序员能理解它们的所有细微之处。

不用说,这本书也是极力推荐的。

也可以看看


关于显式转换

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

很简单:将null类型转换为Object。有几种情况下这是有用的/必要的,这就是其中之一。

如果我有一个过载,比如说,一个Integer

然后方法调用不明确,出现编译时错误。

JLS 15.12.2.5 选择最具体的方法

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

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

也可以看看

于 2010-06-14T13:28:11.843 回答
5

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

顺便说一句,Java 约定是对类使用大写名称,即Another.

于 2010-06-14T12:53:31.433 回答
1

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

于 2010-06-14T12:56:01.600 回答