3

考虑以下代码

public class Foo
{

  int value;
  public Foo (final String str, Object ... bug)
  {
    System.out.println ("Should work! 1");
  }

  public Foo (final String str, final int value, Object ... bug)
  {
     this.value = value;
    System.out.println ("Should work! 2");
  }

  public static void main (String[]args)
  {
    Foo f = new Foo ("Foo", 3); //Line 14
    System.out.println(f.value);
  }
}

当我使用 jdk-1.6.x 时,我成功地编译了它。但是在升级到 jdk-1.7 时它给了我错误:

Foo.java:18: error: reference to Foo is ambiguous, both constructor Foo(String,Object...) in Foo and constructor Foo(String,int,Object...) in Foo match Foo f = new Foo ("Foo", 3); //Line 14

所以为了避免这个错误,我将第二个 Ctor 更改为

  public Foo (final String str, final Integer value, Object ... bug)
  {
     this.value = value;
    System.out.println ("Should work! 2");
  }

这样它就可以自动装箱为 Integer 并跳过编译错误。

几个问题:
1)这是一个好习惯吗?如果没有那么还有其他方法吗?
2)为什么java开发人员会决定给出错误而不是允许它?

4

2 回答 2

4

这是设计使然,也是 Java 6 和 Java 7 之间已知的不兼容区域,因为重载解析算法在 Java 7 中已修复。在 Java 5 和 6 中,以下代码无法编译:

class Test {
    void foo(int... i) {}
    void foo(double... d) {}

    void test() {
       foo(1,2,3);
    }
}

编译器会抱怨调用不明确。但这不是真的,因为double它比更通用int,因此int在这种情况下是最具体的选项。

但是,此修复导致不兼容(查看发行说明;搜索“varargs”)。结果是你不能选择最具体的方法intObject因为两者都不是另一个的子类型。所以这不应该编译。但是,您可以使用Integer, 因为Integer是 的子类型,Object在这种情况下它是最具体的选项,因此编译器可以选择它。

发行说明中的​​相关部分:

虽然javac编译器接受的代码比 JDK 7 之前的代码多,但在以下情况下,此修复也会导致轻微的源不兼容:

class Test {
    void foo(int... i) {}
    void foo(Object... o) {}

    void test() {
       foo(1,2,3);
    }
}

此代码在 JDK 6 中编译(最具体的方法是foo(int...))。此代码无法在 JDK 7 下编译。根据15.12.2.5,无法在 和 之间进行选择foo(int...)foo(Object...)因为既不int是 的子类型Object,也不Object是 的子类型int。这个程序应该被禁止(事实上,它一开始就不应该被允许)。

不兼容的性质:行为和来源

射频:6199075

于 2013-04-02T17:50:48.673 回答
1

为什么java开发人员会决定给出错误而不是允许它?

由于在 JDK 7 中感知var-args 的方式发生了变化,因此发生错误。

1)这是一个好习惯吗?如果没有那么还有其他方法吗?

虽然您可以使用整数来解决这个问题,但类 Foo 最初有一个 int 作为其成员变量,我会保持这种状态。请注意,Integer value;现在可以接受 null。检查代码中的 null 并用于value.intValue()将值分配给成员变量。

未捕获的 NPE 和性能是自动装箱/拆箱的大麻烦。

于 2013-04-02T18:01:46.607 回答