【问题标题】:How is the Java compiler able to distinguish between those two constructors/methods?Java 编译器如何区分这两个构造函数/方法?
【发布时间】:2012-10-18 16:44:48
【问题描述】:
public class MyClass {

    private String string;
    private Object[] objects;

    // constructor 1
    public MyClass(String string, Object... objects) {
        this.string = string;
        this.objects = objects;
    }

    // constructor 2
    public MyClass(String string) {
        this.string = string;
    }

    public static void main(String[] args) {
        MyClass myClass = new MyClass("foobar");
    }

}

在这种情况下,Java 编译器是如何决定使用constructor 2 而不是constructor 1 的?为什么没有The constructor ... is ambiguous或出现类似错误?

PS:这个问题也适用于经典方法

【问题讨论】:

标签: java variadic-functions ambiguous


【解决方案1】:

var-args 方法/构造器将被选择只有当没有 non-var-arg 方法/构造器。所以很清楚为什么编译器选择MyClass(String string)

【讨论】:

  • 并非所有情况都如此,请参阅JLS 15.2.2 中的这个 sn-p:例如,在已经声明 m(Object) 的类中声明 m(Object...) ) 导致不再为某些调用表达式(例如 m(null))选择 m(Object),因为 m(Object[]) 更具体。
  • 加入自动(取消)装箱以引起更多混乱......自 Java 5 以来,方法解析变得很棘手。我认为@Keppil 提到的情况至少会导致编译器警告。
【解决方案2】:

它总是被调用的最具体的方法。

new MyClass("foobar");

搜索以调用将String 类型的对象作为唯一参数的构造函数。

并且,如果匹配 non-var-args 方法不存在,则将使用 var-args 方法。

【讨论】:

    【解决方案3】:

    据我了解,可变参数构造函数和方法只是语法糖,它转换为数组声明。因此,您在编译期间的构造函数 1 几乎等于:

    public MyClass(String string, Object[] objects) {
        this.string = string;
        this.objects = objects;
    }
    

    意思是,如果你想通过以下代码构造MyClass的实例:

    MyClass obj = new MyClass("Hello", "1", "2");
    

    等于:

    MyClass obj = new MyClass("Hello", new Object[]{"1", "2"} );
    

    【讨论】:

    • 不完全相等,因为该构造函数与调用不匹配(而可变参数匹配,只是优先级较低)。
    • @Thilo,是的,你是对的。我只是想通过示例解释概念,但找不到更好的解释。
    【解决方案4】:

    JVM 将寻找精确匹配以将值传递给方法/构造函数中的变量,如果找不到精确匹配,它会将值视为对象。

    【讨论】:

      【解决方案5】:

      第一个答案
      当您有多个构造函数时,构造函数的参数声明彼此不同。初始化类时,Java 将调用与给定参数和类型匹配的正确构造函数。
      例如:如果您创建 2 个具有相同参数的构造函数,那么它将显示 Duplicate method or ambiguous error

      第二个答案
      具有相同和不同原型的方法在java中称为方法overloading
      这就是为什么no The constructor ... is ambiguous error occurs 在承包商的情况下以及在方法的情况下。

      【讨论】:

        【解决方案6】:

        jls-15.12.2 声明编译器将首先查找最佳匹配,而不使用自动装箱或 var agrs。 Constructor #2 适合你的情况。

        如果它不存在,将应用第一个自动装箱,即任何参数超类为 String 的方法,即 Object 将被调用。

           // constructor 2
            public MyClass(Object string) {
                this.string = string.toString();
            }
        

        现在,即使应用了自动装箱,编译器也无法找到最佳匹配,它会选择 var args。因此,如果您从代码中删除构造函数 2,将调用第一个构造函数。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-07-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-09-07
          • 2017-03-26
          • 1970-01-01
          • 2012-10-07
          相关资源
          最近更新 更多