Java:重载构造函数之间的选择

ewo*_*wok 35 java compiler-errors ambiguous-call

根据这个问题,当尝试在不明确的重载构造函数之间进行选择时,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);
    }
}
Run Code Online (Sandbox Code Playgroud)

它会打印出来

"地图"

但是,我试图找出"最具体"的含义.我认为这意味着"最不模糊",如"可能指的是最不可能的类型".在这种情况下,Object可能是任何不是原始的东西,而Map可能只是Map? 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{}
Run Code Online (Sandbox Code Playgroud)

"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{}
Run Code Online (Sandbox Code Playgroud)

我认为它应该打印E,因为E可能只涉及一种已知类型,而A可能指的是两个(AB).但它给出了一个模糊的引用错误.

它是如何实际选择构造函数的?我仔细阅读了文档,但坦率地说,我无法理解它如何确定特异性.我希望能够描述为什么它无法确定哪个E更具体A.

Jon*_*eet 45

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

例如,有从隐式转换StringObject,但反过来是不正确的,那么String是不是更具体Object.

同样有从隐式转换BA,但反过来是不正确的,那么B是不是更具体A.

随着AE有没有从转换-但是,也不是比其他更具体的AE,并没有从转换EA.这就是重载解析失败的原因.

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

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

所以如果你有:

void foo(String x)
void foo(Object x)
Run Code Online (Sandbox Code Playgroud)

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

  • 你碰巧知道"复杂"(选择你想要的任何指标)Java的重载分辨率是多少?例如,C♯的重载分辨率在NP中,实际上,您可以在一组重载中编码任何3-SAT问题,并让编译器为您解决. (3认同)

Cod*_*roc 9

在声明JSL§15.12.2.5答案之后,

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

情况1

  • 你可以在构造函数中Object传递任何东西,但是Map在第一个构造函数中我们不能传递任何东西.因此无论我在Map构造函数中传递的是什么,都可以通过Object构造函数来处理,这就是为什么Test(Map map)会变成特定的mote.

案例2

  • 自从B扩展以来A,这里的Test(B b)构造函数变得更具体.我们可以通过BTest(A a)感谢继承.

案例3

  • 在这种情况下,没有直接转换来描述更具体的方法,并且导致模糊.


Jor*_*rdi 6

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