导语:
对于 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) { ... }
时,传进1,肯定会报错,这是其实在编译阶段,会将传进去的
printArr方法
转换为
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("可变参数");
}
}
输出结果 :
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("可变参数");
}
}
对于上面的代码,运行结果是什么呢?
抱歉,编译器直接报错,因为调用的不清楚是哪个方法. 因此直接报错.如果传入1的话,可以通过将1转为
int ... intArr
满足该方法
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");
原因 : 因为父类参数列表是数组,因此传入字符串类型肯定会报错.如果父类参数列表为可变参数的话,子类是数组类型.那么在编译阶段会将这个语句变为
base.print("hello");
上图形式也属于重写,指向子类的父类调用
print方法
时,将调用子类重写的方法.这是既可以传数组,也可以传递多个String类型的参数.
3.6 如果向可变长参数的方法传入空参的话,将会new一个对应类型的数组,且长度为0.
如果传入null的话 :
反编译后 :
直接传入null,形式未改变.