可变参数的方法,在Java中重载(Varargs in method overloading in

2019-06-18 12:21发布

下面的代码无法编译。

package varargspkg;

public class Main {

    public static void test(int... i) {
        for (int t = 0; t < i.length; t++) {
            System.out.println(i[t]);
        }

        System.out.println("int");
    }

    public static void test(float... f) {
        for (int t = 0; t < f.length; t++) {
            System.out.println(f[t]);
        }

        System.out.println("float");
    }

    public static void main(String[] args) {
        test(1, 2);  //Compilation error here quoted as follows.
    }
}

发出编译时错误。

参照测试是不明确的,在varargspkg.Main匹配在两个varargspkg.Main方法测试(INT ...)和方法试验(浮动...)

这似乎是因为很明显在该方法调用中的参数值test(1, 2); 可以晋升到int以及float

如果这些参数中的任何一个或两个由后缀Ff ,它编译。


如果我们然而,表示与相应的包装类型的方法中的签名接收参数如下

public static void test(Integer... i) {
    System.out.println("Integer" + Arrays.asList(i));
}

public static void test(Float... f) {
    System.out.println("Float" + Arrays.asList(f));
}

然后该呼叫的方法test(1, 2); 不发出任何编译错误。 在这种情况下将被调用的方法是一个接受一个Integer可变参数参数(第一个在前面的片段)。

为什么在这种情况下,误差在第一种情况不报? 看来,自动装箱和自动型的推广都在这里应用。 首次应用于自动装箱,这样的错误得到解决?

甲骨文的文档说,

一般来说,你不应该重载可变参数的方法,或将难以程序员找出哪些超载被调用。

在这最后一句链接 。 它然而,对于更好地理解可变参数的缘故。

还添加以下代码编译就好了。

public class OverLoading {

    public static void main(String[] args) {
        load(1);
    }

    public static void load(int i) {
        System.out.println("int");
    }

    public static void load(float i) {
        System.out.println("float");
    }
}

编辑:

以下是快照指示编译错误。 我创建了一个新的应用程序,因此包名是不同的。

我使用的是JDK 6。

Answer 1:

您可以WidenBox ,但你不能两者都做,除非你是boxing and wideningObject (一个int,整数(拳击),然后整数到对象(扩大)是合法的,因为每个类的子类Object ,所以它是可能的Integer要传递给Object参数)

同样的intNumber也是合法的(INT - >整数- >号)由于编号是父类的Integer这是可能的。

让我们来看看在你的榜样: -

public static void test(Integer...i)

public static void test(Float...f)

有选择其中重载方法来选择,当拳击,加宽,和VAR-ARGS结合时所遵循的一些规则: -

  1. 原始拓宽使用smallest方法参数可能
  2. 包装类型不能被加宽到另一个包装类型
  3. 您可以从int到整数框,并扩大到对象,但没有龙
  4. 拓宽节拍拳击,拳击击败VAR-ARGS。
  5. 您可以框,然后拓宽(一个int可以成为Object通过Integer
  6. 你不能拓宽,然后盒(一个int不能成为Long
  7. 不能合并VAR-ARGS,有或者是扩大或者拳击

因此,基于上面给出的规则: -

当你传递两个整数上述功能,

  • 根据规则3,它必须首先被Widened ,然后Boxed适应一个Long ,根据规则5(你不能拓宽然后箱),这是非法的。
  • 因此,它是盒装在存储Integer VAR-ARGS。

但是,在第一种情况下,你有方法var-args基本类型: -

public static void test(int...i)
public static void test(float...f)

然后test(1, 2)可以调用这两种方法(因为它们都不是更适合于rule 1适用): -

  • 在第一种情况下这将是var-args
  • 在第二种情况下,将被加宽,然后VAR-ARGS(其是允许的)

现在,当你有一个准确int和一个flost方法: -

public static void test(int i)
public static void test(float f)

然后使用调用test(1)规则1之后,与最小的可能的加宽(即, int被选择其中需要完全没有加宽)。 所以,第一个方法将被调用。

欲了解更多信息,可以参考JLS - Method Invocation Conversion



Answer 2:

在Java中, 1是你如何代表int 。 它可以是自动装箱为实例Integer或晋升为float ,而这也解释了为什么编译器不能对应该调用的方法决定。 但它永远不会被自动装箱为LongFloat (或任何其他类型)。

在另一方面,如果你写1F ,它是一种的表现float ,即可以自动装箱为一个Float (和,本着同样的精神,将永远不会自动装箱到一个Integer或其他任何东西)。



Answer 3:

为什么在这种情况下,误差在第一种情况不报? 看来,自动装箱和自动型的推广都在这里应用。 应用于自动装箱第一错误得到解决?

只是一个意见 - 在可变参数的情况下,JVM实际上已经创建的参数数组。 在整数和浮点数的情况下,很明显应该建立什么类型的数组。 因此,它可能会是毫不含糊错误的原因。

但尽管如此,它是一种混乱的,为什么不能创建一个整数数组,时默认1,3是整数。

看起来这已经在过去这里讨论的SO 可变参数和重载的错误? 并且是INFACT 一个错误 ,根据讨论。



Answer 4:

在Java 6中,问题出在时间instantiation的仿制药的发现这方法可调用之前。

When you write 1,2 
     -> it can be be both int[] or float[] and hence the issue being complained.

When you write 1,2F 
     -> it can be be only float[] and hence the NO issue being complained.

同样的,另外两个选项,也就是

When you write 1F,2 
     -> it can be be only float[] and hence the NO issue being complained.

When you write 1F,2F 
     -> it can be be only float[] and hence the NO issue being complained.

在另一方面,当您使用intfloat ,不存在变量类型实例。 当您使用1 ,则会试图寻找方法与int作为参数,第一个,如果不是,它促进的类型和标识与浮动方法。 如果这两种方法可供选择,分别与int将首先使用。

歧义的问题不会再在Java 7中 ,因为它具有更好的操控性数据类型检查和推广。



文章来源: Varargs in method overloading in Java