有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java调用看起来模棱两可,但在意外的输出下运行得很好

请看这个Java类

class Demo
{
    public static void a(String s)
    {
        System.out.println("string called");
    }
    public static void a(Object a)
    {
        System.out.println("Object called");
    }
    public static void main(String...asrgs)
    {
        a(null);
    }
}

这段代码的输出是“stringcalled”,但我无法理解编译器如何在对象字符串之间解析

此外,请检查此代码片段

class Demo
{
    public static void a(String s)
    {
        System.out.println("string called");
    }
    public static void a(Integer n)
    {
        System.out.println("number called");
    }
    public static void a(Object a)
    {
        System.out.println("Object called");
    }
    public static void main(String...asrgs)
    {
        a(null);
    }
}

这里我们得到了一个与不明确调用相关的编译时错误(这是很明显的)。 有什么好的解释吗


共 (1) 个答案

  1. # 1 楼答案

    答案在于§15.12.2的JLS:

    The second step searches the type determined in the previous step for member methods. This step uses the name of the method and the argument expressions to locate methods that are both accessible and applicable, that is, declarations that can be correctly invoked on the given arguments.

    There may be more than one such method, in which case the most specific one is chosen. The descriptor (signature plus return type) of the most specific method is the one used at run time to perform the method dispatch.

    (我的重点)

    。。。和§15.12.2.5,上面一节提到的,它有专一性规则的全部细节,但也有这个方便的摘要:

    The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.

    在第一个示例中,a(String)a(Object)更具体,因此编译器知道使用哪一个,并且很高兴。在第二个示例中,a(String)a(Integer)都比a(Object)更具体,但两者都适用于null,并且它们处于不同的谱系中(StringString > ObjectIntegerInteger > Number > Object),这造成了编译器抱怨的歧义

    如果他们在相同的谱系中,就不会有歧义,因为只有一个适用的最具体的选项。例如:

    class Base {
    }
    class Child extends Base {
    }
    class GrandChild extends Child {
    }
    public class Example {
    
        public static final void main(String[] args) {
            a(null);
        }
    
        public static void a(Base b) {
            System.out.println("Base");
        }
    
        public static void a(Child b) {
            System.out.println("Child");
        }
    
        public static void a(GrandChild b) {
            System.out.println("GrandChild");
        }
    }
    

    它打印"GrandChild",因为a(Child)a(GrandChild)都比a(Object)更具体,而a(GrandChild)a(Child)更具体