为什么输出是这样的?

2022-09-04 05:48:03
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);
    }
}

当我尝试执行此命令时,我得到

这是采用字符串的方法

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


答案 1

根据Java语言规范,在重载方法的情况下,两种方法都可以处理提供的参数,选择具有更具体参数的方法。因为 比 ( 扩展 ) 更具体,因此选择并调用。StringObjectStringObjectvoid method(String)


答案 2

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

JLS 15.12.2.5 选择最具体的方法

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

A 是 a,但不是所有的 is-a 。因此, 比 更具体,因此为什么在上面的示例中选择重载。StringObjectObjectStringStringObjectString


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

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

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


最后,我将引用《有效的 Java 第 2 版》第 41 项:明智地使用重载

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

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

另请参见


关于显式强制转换

那么我该如何用参数调用重载呢?Objectnull

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

如果我有一个重载,比如说,一个 ?Integer

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

JLS 15.12.2.5 选择最具体的方法

可能没有一种方法是最具体的,因为有两种或两种以上方法具有最大的特异性。在本例中 [...除了一些例外],我们说方法调用是模棱两可的,并且发生了编译时错误。

若要解决不明确性,可以再次将(或其他表达式)强制转换为所需的重载类型。null

另请参见


推荐