Java:在重载构造函数之间进行选择

2022-09-01 06:45:14

根据这个问题,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);
    }
}

它将打印

“地图”

但是,我试图弄清楚“最具体”的确切含义。我以为它的意思是“最不模糊的”,就像“可能指最少的可能类型”一样。在此上下文中,可能是任何不是基元的东西,而可能只是 或 。基本上,我假设选择哪个类更接近继承树的叶子。当一个类是另一个类的子类时,这有效:ObjectMapMap? 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{}

“B”

然后我想出了这个:

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{}

我认为它应该打印,因为可能只指一种已知类型,而可能指两种(和)。但它给出了一个模棱两可的引用错误。EEAAB

它实际上是如何选择构造函数的?我通读了文档,但坦率地说,我无法完全理解它如何确定特异性。我希望能够确切地解释为什么它不能确定这比更具体。EA


答案 1

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

例如,有一个从 到 的隐式转换,但反之则不然,因此比 更具体。StringObjectStringObject

同样,有一个从 到 的隐式转换,但反之则不然,因此比 更具体。BABA

但是,使用 和,两者都不比另一个更具体 - 没有从 到 的转换,也没有从 到 的转换。这就是过载解析失败的原因。AEAEEA

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

非正式的直觉是,如果第一个方法处理的任何调用都可以在没有编译时错误的情况下传递给另一个方法,则一种方法比另一个方法更具体。

因此,如果您有:

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

每个 由 处理的调用都可以由 处理,但事实并非如此。(例如,您可以调用,但 无法由 处理。foo(String)foo(Object)foo(new Object())foo(String)


答案 2

JSL§15.12.2.5以下声明回答了以下问题:

非正式的直觉是,如果第一个方法处理的任何调用都可以在没有编译时错误的情况下传递给另一个方法,则一种方法比另一个方法更具体

案例1

  • 你可以在构造函数中传递任何东西,而我们不能传递除第一个构造函数之外的任何东西。因此,我在构造函数中传递的任何内容都可以由构造函数处理,这就是为什么变得特定于微尘的原因。ObjectMapMapObjectTest(Map map)

案例 2

  • 由于扩展,这里的构造函数变得更加具体。由于继承,我们可以传递进来。BATest(B b)BTest(A a)

案例 3

  • 在这种情况下,没有直接转换来描述更具体的方法,这会导致歧义

推荐