Java在1.5之后允许方法使用可变参数,可变参数的好处在于:它允许传递0个或者多个参数。比如原来有一段代码如下:
public class Test {
public static void main(String[] args) {
test();
test(new String[]{"a"});
test(new String[]{"a", "b"});
}
private static void test() {
System.out.println(“[]”);
}
private static void test(String[] args) {
System.out.println(Arrays.toString(args));
}
}
使用可变参数之后的代码如下:
public class Test {
public static void main(String[] args) {
test();
test(new String[]{"a"});
test(new String[]{"a", "b"});
}
private static void test(String... args) {
System.out.println(Arrays.toString(args));
}
}
可见,可变参数的功能更加强大,语意包含的范围更广。
我们知道,在Java中,除了8种基本类型之外一切都是类。那么可变参数到底是个什么类呢?来,用代码验证下!
public class Test {
public static void main(String[] args) {
whatClass();
whatClass1();
}
private static void whatClass(String... args) {
System.out.println(args.getClass());
System.out.println(new String[]{}.getClass());
}
private static void whatClass1(int... args) {
System.out.println(args.getClass());
System.out.println(new int[]{}.getClass());
}
}
上面代码的运行结果是:
class [Ljava.lang.String;
class [Ljava.lang.String;
class [I
class [I
可见,可变参数在运行时还是会被JVM转变成一个数组,所以当我们使用可变参数的时候,实际上又一个隐含的过程,就是创建一个数组并且赋初值。当我们对性能敏感时,这一特性可能会坑了我们,为何这样说?看下面的代码:
public class Test {
public static void main(String[] args) {
long start = System.currentTimeMillis();
int sum = 0;
for (int i = 0; i < 10000; i++) {
sum += test1(1);
}
long end = System.currentTimeMillis();
System.out.println(end - start);
start = System.currentTimeMillis();
sum = 0;
for (int i = 0; i < 1000000; i++) {
sum += test2(1);
}
end = System.currentTimeMillis();
System.out.println(end - start);
}
private static int test2(int... args) {
return args[0];
}
private static int test1(int first) {
return first;
}
}
test2的时间大于test1的时间,这种差别随着循环次数的增大越来越明显。这种性能的参数就是可变参数的“功劳”。因此,我们总见到这样的方法重载:
public void fun(int val1){}
public void fun(int val1,int val2){}
public void fun(int val1,int val2,int val3){}
public void fun(int val1,int val2,int val3,int... args){}
当fun方法的大多数调用都是有1-3个参数值的时候,使用上面的方法比仅有一个可变参数的方法性能要好的多,因为很少能用到可变参数的方法。这种例子最常见的就是JDK中的EnumSet类型的of()方法。看过的小伙伴可能对of(E first, E... rest)方法有些疑问,这个方法和of(E first,E second)等方法是“冲突”的啊?
实际上,Java是很聪明的。Java语法规定,可变参数必须在所有参数的最后声明,而且Java会首先寻找满足条件的不包含可变参数的方法,如果没找到,再使用包含可变参数的方法,看下面的例子:
public class Test {
public static void main(String[] args) {
fun(1);
fun(1, 2);
fun(1, 2, 3);
fun(1, 2, 3, 4);
fun(1, 2, 3, 4, 5);
}
private static void fun(int val1) {
System.out.println("fun(int val1)");
}
private static void fun(int val1, int val2) {
System.out.println("fun(int val1, int val2)");
}
private static void fun(int val1, int val2, int val3) {
System.out.println("fun(int val1,int val2,int val3)");
}
private static void fun(int val1, int... args) {
System.out.println("fun(int val1, int val2, int val3, int... args)");
}
}
笔者开设了一个知乎live,详细的介绍的JAVA从入门到精通该如何学,学什么?
提供给想深入学习和提高JAVA能力的同学,欢迎收听https://www.zhihu.com/lives/932192204248682496
提供给想学习云计算的同学,欢迎收听https://www.zhihu.com/lives/1046567982750281728