Java中方法重载的Varargs [英] Varargs in method overloading in Java

查看:118
本文介绍了Java中方法重载的Varargs的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码无法编译。

  package varargspkg; 

公共类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); //编译错误引用如下。
}
}

发出编译时错误。


对test的引用不明确,
varargspkg.Main中的方法test(int ...)和方法测试(float ... )in varargspkg.Main match


这似乎是显而易见的,因为方法中的参数值调用 test( 1,2); 可以提升为 int 以及 float



如果任何一个或两个参数后缀为 F f ,它编译。<​​/ p>




但是,如果我们使用相应的包装类型表示方法签名中的接收参数,如下所示

  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 varargs参数(前面代码片段中的第一个)的方法。



在这种情况下,为什么在第一种情况下没有报告错误?这里似乎都应用了自动装箱和自动类型提升。是否先应用自动装箱以便解决错误?



Oracle文档说,


一般来说,你不应该重载varargs方法,否则
将很难让程序员弄清楚哪些重载被
调用。






我正在使用JDK 6.

解决方案

你可以加宽 Box 但你不能同时做到这两点,除非你装箱和加宽 Object (一个int到Integer(Boxing)然后是Integer到Object(Widening)是合法的,因为每个类都是 Object 的子类,所以可以将 Integer 传递给 Object 参数)



类似地, int Number 也是合法的(int - > Integer - > Number)
由于Number是 Integer的超类,因此可以。



让我们在你的例子中看到这一点: -

  publ ic static void test(Integer ... i)

public static void test(Float ... f)

选择要选择的重载方法时,遵循一些规则,当组合Boxing,Widening和Var-args时: -


  1. 原始扩展使用最小方法参数

  2. 包装类型无法扩展到另一种包装类型

  3. 你可以从int到整数并加宽到对象但不到长

  4. 加宽节拍拳击,拳击节拍Var-args。

  5. 你可以Box然后加宽(一个 int 可以通过<$ c变成对象 $ c>整数)

  6. 你不能加宽然后Box(一个 int 不能变成

  7. 你不能将var-args与加宽或装箱结合起来

因此,基于以上给定的规则: -



当您将两个整数传递给上述函数时,




  • 根据规则3,它必须是第一个加宽然后
    装箱以装入 Long ,根据规则5(你是非法的)不能加宽,然后Box)。

  • 因此,它被装箱以存储在整数 var-args。



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

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

然后 test(1,2)可以调用两者方法(因为它们都不适合规则1 申请): -




  • 在第一种情况下,它将是 var-args

  • 在第二种情况下,它将是加宽,然后是Var-args(这是允许的)



现在,当你的方法只有一个int和一个flost: -

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

然后开启使用 test(1)调用,遵循规则1,并尽可能小地扩展(即选择 int ,其中根本不需要加宽)。因此将调用第一个方法。



有关更多信息,请参阅 JLS - 方法调用转换


The following code doesn't compile.

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

A compile-time error is issued.

reference to test is ambiguous, both method test(int...) in varargspkg.Main and method test(float...) in varargspkg.Main match

It seems to be obvious because the parameter values in the method call test(1, 2); can be promoted to int as well as float

If anyone or both of the parameters are suffixed by F or f, it compiles.


If we however, represent the receiving parameters in the method signature with respective wrapper types as follows

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));
}

then the call to the method test(1, 2); doesn't issue any compilation error. The method to be invoked in this case is the one that accepts one Integer varargs parameter (the first one in the preceding snippet).

Why is in this case the error as in the first case not reported? It appears that auto-boxing and automatic type promotion are both applied here. Is auto-boxing applied first so that the error is resolved?

The Oracle docs says,

Generally speaking, you should not overload a varargs method, or it will be difficult for programmers to figure out which overloading gets called.

The last sentence in this link. It's however for the sake of better understanding varargs.

Also to add below code compiles just fine.

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");
    }
}


EDIT:

The following is the snap shot that indicates the compilation error. I have created a new application therefore the package name is different.

I'm using JDK 6.

解决方案

You can either Widen or Box but you cannot do both, unless you are boxing and widening to Object (An int to Integer(Boxing) and then Integer to Object(Widening) is legal, since every class is a subclass of Object, so it is possible for Integer to be passed to Object parameter)

Similarly an int to Number is also legal (int -> Integer -> Number) Since Number is the super class of Integer it is possible.

Let's see this in your example: -

public static void test(Integer...i)

public static void test(Float...f)

There are some rules that are followed when selecting which overloaded method to select, when Boxing, Widening, and Var-args are combined: -

  1. Primitive widening uses the smallest method argument possible
  2. Wrapper type cannot be widened to another Wrapper type
  3. You can Box from int to Integer and widen to Object but no to Long
  4. Widening beats Boxing, Boxing beats Var-args.
  5. You can Box and then Widen (An int can become Object via Integer)
  6. You cannot Widen and then Box (An int cannot become Long)
  7. You cannot combine var-args, with either widening or boxing

So, based on the above given rules: -

When you pass two integers to above functions,

  • according to rule 3, it will have to be first Widened and then Boxed to fit into a Long, which is illegal according to rule 5 (You cannot Widen and then Box).
  • So, it is Boxed to store in Integer var-args.

But in first case, where you have methods with var-args of primitive types: -

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

Then test(1, 2) can invoke both the methods (Since neither of them is more suitable for rule 1 to apply) : -

  • In first case it will be var-args
  • In second case, it will be Widening and then Var-args (which is allowed)

Now, when you have methods with exactly one int and one flost: -

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

Then on invoking using test(1), rule 1 is followed, and smallest possible widening (i.e. the int where no widening is needed at all) is chosen. So 1st method will be invoked.

For more information, you can refer to JLS - Method Invocation Conversion

这篇关于Java中方法重载的Varargs的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆