Java中var-args和装箱的问题

8

我有一个与以下代码片段相关的问题:

    class VarArgsTricky {
    static void wide_vararg(long... x) {
        System.out.println("long...");
    }

    static void wide_vararg(Integer... x) {
        System.out.println("Integer...");
    }

    public static void main(String[] args) {
        int i = 5;
        wide_vararg(i, i, i); // needs to widen and use var-args
        Long l = 9000000000l;
        wide_vararg(l, l); // prints sucessfully "long..."
    }
}

第一次调用wide_vararg无法编译(显示该方法不明确),而第二次可以成功编译。

这种行为有何解释? 谢谢!


如果这不仅仅是关于重载的实验,请阅读《Effective Java SE》第41条:谨慎使用重载。 - TJR
这只是一个实验,只是为了解决OCPJP认证考试中的一个潜在问题。 - Ariel Chelsău
2个回答

10

由于编译器可以进行以下两种操作之一,因此第一个 wide_vararg 调用是模糊不清的:

  • int 扩展为 long 并调用第一个 wide_vararg 方法,或者
  • int 自动装箱为 Integer 并调用第二个 wide_vararg

然而,它不知道应该采取哪种操作,因此拒绝编译这种模糊不清的方法调用。如果您想使第一个调用编译通过,请将 i 声明为 Integerlong,而不是 int


1
根据K&B SCJP 6书籍,扩展优于装箱,而装箱优于var-args。因此,第一次调用应该选择扩展而不是自动装箱。如果i被声明为Integer,则也无法编译。当然,long类型可以工作。问题仍然存在:为什么它不选择扩展而不是自动装箱? - Ariel Chelsău
嗯,你说得对。我还不确定为什么。该死的,这可能是编译器的一个错误。但是,无论是扩宽还是装箱,都打不过varargs。因为没有非varargs的选择,所以这不是问题。 - Matt Ball
1
没有非varargs的选择,这是真的。可能是某种编译器bug或一些不太为人知的特性。了解确切情况会很有趣。 - Ariel Chelsău
相关链接:https://dev59.com/fnE85IYBdhLWcg3w9orw - Matt Ball

1

当调用可变参数方法时,参数在编译时被转换为该类型的数组。

在第一次调用中,参数被转换为int[]。由于Java中的所有数组都是Object类的直接子类型,原始扩展的概念不适用,在这种情况下,两个重载变得同样适用,因为long[]和Integer[]处于相同的级别。因此存在歧义。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接