【问题标题】:Java: selection between overloaded constructorsJava:重载构造函数之间的选择
【发布时间】:2016-12-23 02:49:53
【问题描述】:

根据this question,当尝试在模棱两可的重载构造函数之间进行选择时,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 可能只是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{}

“乙”

然后我想出了这个:

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

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

实际上是如何选择构造函数的?我通读了the docs,但坦率地说,我不太明白它是如何确定特异性的。我希望能准确描述为什么它无法确定 E 比 A 更具体。

【问题讨论】:

  • 不可能是这样的:? extends String,字符串类是final
  • @ΦXocę웃Пepeúpaツ 好点。我会解决的

标签: java compiler-errors ambiguous-call


【解决方案1】:

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

例如,有一个从String 到Object 的隐式转换,但反之则不然,所以String 比Object 更具体。

同样存在从B 到A 的隐式转换,但反之则不然,因此B 比A 更具体。

但是,对于 A 和 E,两者都不比另一个更具体 - 没有从 A 到 E 的转换,也没有从 E 到 A 的转换。这就是重载解析失败的原因。

JLS 的相关位其实是15.12.2.5,其中包含的可能会让你更容易理解:

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

如果你有:

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

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

【讨论】:

  • 这句话正是我要找的。我想我没有读那么远。
  • 您是否知道 Java 的重载解决方案有多“复杂”(选择您想要的任何指标)?例如。 C♯ 的重载解析是在 NP 中,实际上,您可以将任何 3-SAT 问题编码为一组重载,并让编译器为您解决。
  • @JörgWMittag:我根本不知道,恐怕:(
  • 我怎样才能调用最不具体的方法??如果我有 foo(Object o);和 foo(String s);。我想调用 foo(Object o)。我该怎么办?
  • @SagarNayak:将参数转换为Object,这样foo(String) 不适用。
【解决方案2】:

JSL§15.12.2.5 的以下声明回答了这个问题,

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

案例 1

  • 您可以在构造函数中传递任何采用Object 的内容,而我们不能在第一个构造函数中传递除Map 之外的任何内容。因此,无论我在 Map 构造函数中传递什么,都可以由 Object 构造函数处理,这就是为什么 Test(Map map) 变得更具体。

案例 2

  • 由于B 扩展了A,因此Test(B b) 构造函数变得更加具体。由于继承,我们可以在Test(A a) 中传递B。

案例 3

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2021-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多