天天看点

参数数量可变的方法 - Java

导语:

对于​

​public static void changeVarLength(String ... str) { ...; }​

​这种形式参数都见到过吧,后面就会将参数数量可变的方法需要注意的事项进行讲解,通过举例来实际证明.

一、可变参数的定义

在jdk 1.5 之后 , 方法的参数可以通过省略号​

​...​

​​来作为一部分 , 即​

​(String ... str)​

​​ , 这种形式其实是语法糖 , 实际上相当于 ​

​(String[ ] str)​

​ .

通过​

​...​

​这种形式的参数 , 表明这个方法可以接受任意数量的对象.

为什么这里说的是接受的是任意数量的对象呢?常量不行么?比如传进去一个int类型的1,会怎样呢?

答 : 其实很好理解,传进去的肯定是对象类型, ​

​...​

​​本质是语法糖 , 比如​

​public static void printArr(int ... i){ ... }​

​​实际上相当于​

​public static void printArr(int[ ] i) { ... }​

​​ , 那么当你调用​

​printArr方法​

​​时,传进1,肯定会报错,这是其实在编译阶段,会将传进去的​

​1​

​​转换为​

​new int[] {1}​

​传进去的是一个数组.
public class VarPara {
  public static void changePara(Object ... obj) {
    for(Object o : obj) {
      System.out.println(o);
    }
}      

二、可变参数方法的调用

调用时可以是传进去任意数量的参数

例 :

changePara();

changePara(1);

changePara(1, 2);

对于参数,除了会将参数绑定到数组上,必要时还会进行自动装箱.

例如 :

public class ChangeVarLength {
    public static void main(String[] args) {
        changePara();
        changePara(1);
        changePara(1, 2);
    }

    public static void changePara(Object... obj) {
        for (Object o : obj) {
            System.out.println(o);
        }
    }
}      

反编译后代码 :

public class ChangeVarLength
{

  public ChangeVarLength4()
  {
  }

  public static void main(String args[])
  {
    changePara(new Object[0]);
    changePara(new Object[] {
      Integer.valueOf(1)
    });
    changePara(new Object[] {
      Integer.valueOf(1), Integer.valueOf(2)
    });
  }

  public static transient void changePara(Object obj[])
  {
    Object aobj[] = obj;
    int i = aobj.length;
    for (int j = 0; j < i; j++)
    {
      Object o = aobj[j];
      System.out.println(o);
    }

  }
}      

三、可变参数的使用原则

3.1 一个方法只能有一个可变的参数,并且这个参数必须是该方法的最后一个参数

正确形式 :

public static void test1(String ... str) { // TODO }
public static void test2(String str, String ... str1) { // TODO }
public static void test3(String str, String str1, String ... str2) { // TODO }      

3.2 如果重载了可变参数的方法, 优先调用匹配定长参数的方法,不定参数的那个重载方法是最后被选中的。

public class ChangeVarLength5 {
    public static void main(String[] args) {
        chanVar(1);
        chanVar();
        chanVar(1, 2);
    }

    public static void chanVar(int intArr) {
        System.out.println("具体参数");
    }

    public static void chanVar(int... intArr) {
        System.out.println("可变参数");
    }
}      

输出结果 :

参数数量可变的方法 - Java

3.3 对于可变参数的方法,既可以接受多个形式参数类型的参数,也可以接受形式参数类型的数组; 但是方法参数为数组只能接受数组.

在方法调用时也提到,调用时,如果传入的是​

​(1, 2, 3)​

​​,则会在编译的时候将其绑定数组为​

​new int[ ] {1, 2, 3}​

​​, 所以对于可变参数方法,可以接受两种形式的参数.

然而对于方法参数为数组的方法而言, 则只能接受数组类型的参数.否则将会报错!

3.4 方法调用时,同时满足两个方法,编译器将会产生错误

public class ChangeVarLength6 {
    public static void main(String[] args) {
        chanVar(1);
        chanVar(1, 2);
        chanVar();
    }

    public static void chanVar(int ... intArr) {
        System.out.println("具体参数");
    }

    public static void chanVar(int i, int... intArr) {
        System.out.println("可变参数");
    }
}      

对于上面的代码,运行结果是什么呢?

抱歉,编译器直接报错,因为调用的不清楚是哪个方法. 因此直接报错.
参数数量可变的方法 - Java
如果传入1的话,​

​int ... intArr​

​可以通过将1转为​

​new int[ ] {1}​

​满足该方法​

​chanVar(int ... intArr)​

​, 同时也可以满足​

​chanVar(int i, int... intArr)​

​,将传入的转为​

​chanVar(1, new int[0]);​

​,因此分不清该调用哪一个了而报错.

3.5 对于继承,子类将父类方法的参数列表数组形式改为可变参数数量属于重写,但是指向子类的父类调用该方法是形参列表由父类决定.

public class ChangeVarLength2 {
    public static void main(String[] args) {
        // 向上转型
        Base base = new Sub();
        base.print("hello");

        // 不转型
        Sub sub = new Sub();
        sub.print("hello");
    }
}

// 基类
class Base {
    void print(String[] args) {
        System.out.println("Base......test");
    }
}

// 子类,覆写父类方法
class Sub extends Base {
    @Override
    void print(String... args) {
        System.out.println("Sub......test");
    }
}      
对于​

​base.print("hello");​

​直接编辑器报错
参数数量可变的方法 - Java
原因 : 因为父类参数列表是数组,因此传入字符串类型肯定会报错.
如果父类参数列表为可变参数的话,子类是数组类型.那么​

​base.print("hello");​

​在编译阶段会将这个语句变为
参数数量可变的方法 - Java
参数数量可变的方法 - Java

上图形式也属于重写,指向子类的父类调用​

​print方法​

​时,将调用子类重写的方法.这是既可以传数组,也可以传递多个String类型的参数.

3.6 如果向可变长参数的方法传入空参的话,将会new一个对应类型的数组,且长度为0.

如果传入null的话 :

参数数量可变的方法 - Java

反编译后 :

参数数量可变的方法 - Java

直接传入null,形式未改变.