35

根据这个问题,当尝试在模棱两可的重载构造函数之间进行选择时,Java 将选择“最具体”的选项。在这个例子中:

public class Test{
    private Test(Map map){
        System.out.println("Map");
    }
    private Test(Object o){
        System.out.println("Object");
    }
    public static void main(String[] args){
        new Test(null);
    }
}

它会打印

“地图”

但是,我试图弄清楚“最具体”的确切含义。我认为它的意思是“最不模棱两可”,如“可能指的是最少可能的类型”。在这种情况下,Object可能是任何不是原始的东西,而Map可能只是Mapor ? extends Map。基本上,我假设无论哪个类更接近继承树的叶子,都会被选中。当一个类是另一个类的子类时,这是有效的:

public class Test{
    private Test(A a){
        System.out.println("A");
    }
    private Test(B b){
        System.out.println("B");
    }
    public static void main(String[] args){
        new Test(null);
    }
}

class A{}

class B extends A{}

“乙”

然后我想出了这个:

public class Test{
    private Test(A a){
        System.out.println("A");
    }
    private Test(E e){
        System.out.println("E");
    }
    public static void main(String[] args){
        new Test(null);
    }
}

class A{}

class B extends A{}

class C{}

class D extends C{}

class E extends D{}

我认为它应该 print E,因为E可能只指一种已知类型,而A可能指两种(AB)。但它给出了一个模棱两可的参考错误。

它实际上是如何选择构造函数的?我通读了文档,但坦率地说,我不太明白它是如何确定特异性的。我希望能准确描述为什么它不能确定EA.

4

3 回答 3

45

它不是基于可转换为参数类型的类型的数量 - 由于隐式转换,对于一个重载有效的任何值是否对另一个有效。

例如,有一个从Stringto的隐式转换Object,但反过来不正确,所以StringObject.

同样,有一个从Bto的隐式转换A,但反过来不正确,所以BA.

A然而,E没有一个比另一个更具体——没有从 to 的转换,A也没有从toE的转换。这就是重载决议失败的原因。EA

JLS 的相关位实际上是15.12.2.5,其中包括可能使您更容易理解的内容:

非正式的直觉是,如果第一个方法处理的任何调用都可以传递给另一个方法而不会出现编译时错误,那么一个方法比另一个方法更具体。

因此,如果您有:

void foo(String x)
void foo(Object x)

由 处理的每个调用foo(String)都可以由 处理foo(Object),但反之则不然。(例如,您可以打电话foo(new Object()),但 . 无法处理foo(String)。)

于 2016-08-16T16:25:03.667 回答
9

JSL§15.12.2.5的陈述之后回答说,

非正式的直觉是,如果第一个方法处理的任何调用可以传递给另一个方法而不会出现编译时错误,那么一个方法比另一个方法更具体。

情况1

  • 你可以在构造函数中传递任何需要的东西,Object而我们不能Map在第一个构造函数中传递任何东西。因此,无论我在Map构造函数中传递什么,都可以由Object构造函数处理,这就是为什么Test(Map map)变得特定的原因。

案例2

  • 由于Bextends A,这里的Test(B b)构造函数变得更加具体。因为我们可以通过继承B来传递。Test(A a)

案例3

  • 在这种情况下,没有直接转换来描述更具体的方法,这会导致歧义
于 2016-08-16T16:25:25.373 回答
6

这种行为是因为 E 并不比 A 更具体,因为它们属于不同的层次结构,因此无法进行比较。因此,当您传递 null 时,Java 无法知道要使用哪个层次结构。

于 2016-08-16T16:24:53.700 回答