可变参数列表可以应用在参数个数或者是类型未知的场合。由于所有的类都继承自Object,所以我们可以创建一个Object数组作为参数,具体的做法如下所示:
class A {}
public class VarArgs {
static void printArray(Object[] args) {
for (Object obj: args) {
System.out.print(obj + " ");
}
System.out.println();
}
public static void main(String[] args) {
printArray(new Object[] {47, (float) 3.14, 11.11});
printArray(new Object[] {"one", "two", "three"});
printArray(new Object[] {new A(), new A(), new A()});
}
}
输出:
47 3.14 11.11
one two three
A@15db9742 A@6d06d69c A@7852e922
printArray()
函数的参数是Object数组,这样我们就实现了可变参数列表,但是以上的方式实在是太笨拙了,所以在 Java 5 之后添加了可变参数列表的特性,我们可以使用以下的方式来令一个方法可以接受可变的参数列表:
public class NewVarArgs {
static void printArray(Object... args) {
for (Object obj: args) {
System.out.print(obj + " ");
}
System.out.println();
}
public static void main(String[] args) {
printArray(47, (float) 3.14, 11.11);
printArray(47, 3.14F, 11.11);
printArray("one", "two", "three");
printArray(new A(), new A(), new A());
printArray((Object[]) new Integer[] {1, 2, 3, 4});
printArray();
}
}
输出:
47 3.14 11.11
47 3.14 11.11
one two three
A@15db9742 A@6d06d69c A@7852e922
1 2 3 4
当我们指定参数之后,编译器实际上会自动地为我们填充数组,所以我们获取的仍然是一个数组,printArray()函数也就可以使用 for-in 进行迭代遍历了。
程序的最后一行表明可变参数的个数可以是0,这可以应用于可选的尾随参数:
public class OptionalTrailingArguments {
static void f(int required, String... trailing) {
System.out.print("required: " + required + " ");
for (String s: trailing) {
System.out.print(s + " ");
}
System.out.println();
}
public static void main(String[] args) {
f(1, "one");
f(2, "two", "three");
f(0);
}
}
输出:
required: 1 one
required: 2 two three
required: 0
以下的例子中展示了非Object类型的可变参数列表,以及可变参数列表转换为数组的情形,如果类表中没有任何的元素,那么会转变为大小为0的数组:
public class VarargType {
static void f(Character... args) {
System.out.print(args.getClass());
System.out.println(" length " + args.length);
}
static void g(int... args) {
System.out.print(args.getClass());
System.out.println(" length " + args.length)
}
public static void main(String[] args) {
f('a');
f();
g(1);
g();
System.out.println("int[]: "+ new int[0].getClass());
}
}
输出为:
class [Ljava.lang.Character; length 1
class [Ljava.lang.Character; length 0
class [I length 1
class [I length 0
int[]: class [I
可变参数列表和自动装箱是可以搭配使用的:
public class AutoboxingVarargs {
public static void f(Integer... args) {
for (Integer i: args) {
System.out.print(i + " ");
}
System.out.println();
}
public static void main(String[] args) {
f(1, 2);
f(4, 5, 6, 7, 8, 9);
f(10, 11, 12);
}
}
可变参数列表方法的重载可能会导致错误的发生:
public class OverloadingVarargs {
static void f(Character... args) {
System.out.print("first");
for (Character c: args) {
System.out.print(" " + c);
}
System.out.println();
}
static void f(Integer... args) {
System.out.print("second");
for (Integer i: args) {
System.out.print(" " + i);
}
System.out.println();
}
static void f(Long... args) {
System.out.println("third");
}
public static void main(String[] args) {
f('a', 'b', 'c');
f(1);
f(2, 1);
f(0);
f(0L);
}
}
输出:
first a b c
second 1
second 2 1
second 0
third
注意被注释掉的最后一行,如果我们调用不带参数的 f() ,那么编译器就不会知道应该调用哪一个方法,最终会导致错误的发生。