这段Java代码的解释是什么?

16

我有以下代码:

public class Main {
     public void method(Object o)
     {
           System.out.println("Object Version");
     }
     public void method(String s)
     {
          System.out.println("String Version");
     }
     public static void main(String args[])
     {
           Main question = new Main();
           question.method(null);//1
     }
}
为什么结果是“String Version”?如果第一个方法接受一个 StringBuffer 对象,为什么会出现编译器错误?另一种情况:如果第一个方法接受一个 StringBuffer 对象,并且我写成 question.method("word");,结果将是“String Version”。为什么?为什么没有编译器错误?

好奇。我本来以为编译器会抱怨,但也许两个参数类之间存在类型关系(String更具体)改变了情况,这是JLS中的一个案例吗?不过StringBuffer的情况很容易,因为它肯定是模棱两可的。 - Donal Fellows
1
@第三个问题:当然不会出现错误。你正在传递一个字符串,因此显然会调用带有字符串参数的方法。编译器没有什么可以混淆的。 - someguy
2个回答

23

JAVA规范指出,在这种情况下,将调用最具体的函数。由于String是Object的子类型,因此将调用第二个方法。 如果将Object更改为StringBuffer,则没有特定的方法,因为StringBuffer不是String的子类型,反之亦然。在这种情况下,编译器不知道调用哪个方法,因此会出现错误。


1

当看到另一个情况时:

包 com.snamellit;

public class Main {
    public void method(Object o) {
        System.out.println("Object Version");
    }

    public void method(String s) {
        System.out.println("String Version");
    }

    public static void main(String args[]) {
        Main question = new Main();
        question.method("word");
    }
}

如果第一个方法使用StringBuffer,第二个方法使用String,则不可能混淆,因为“word”是String而不是StringBuffer。
在Java中,函数/方法的身份取决于3个方面:名称、参数类型(也称为参数签名)和类加载器。由于这两种类型具有不同的参数签名,编译器可以轻松选择正确的方法,并且不会引发错误。

谢谢Peter。我认为应该会出现编译器错误,因为“word”是一个有效的StringBuffer值。 - Mohamad Alhamoud
2
不,它是一个字符串,而不是StringBuffer。StringBuffer是字符串的可变版本,而字符串是不可变的,因此是字面字符串的良好模型。一位智者曾说:“当你怀疑时,试一试”:System.out.println("word".getClass().getName())将打印java.lang.String。 - Peter Tillemans

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接