我们为什么不能只使用数组而不是可变参数列表?

11

在学习Android(doInBackground(Type... params))时,我偶然接触到了varargsStack Overflow的帖子澄清了它的使用方法。

我的问题是,为什么我们不能只使用数组而不是varargs

public void foo(String...strings) {  }

我可以通过将我的可变数量的参数打包在一个数组中,并将其传递给这样的方法来替换这种类型的调用

public void foo(String[] alternativeWay){  }

在Java中,main(String[] args)使用了varargs吗?如果没有,那我们如何将运行时参数传递给它呢?

请提供varargs的优点或用途,并且是否还有其他重要事项需要了解varargs


3
Varargs是一种语法方便的写法。在有了varargs之前,我们通常需要手动编写数组创建表达式。 - Marko Topolnik
@MarkoTopolnik,您能否详细说明一下,主函数呢? - Sainath S.R
1
如果你喜欢,可以声明 main(String... args)。这不会有任何影响。 - Marko Topolnik
正如Marko所说,这只是语法糖。请阅读文档 - http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html - Simon
4个回答

15

唯一的区别在于

foo(String... strings)

foo(String[] strings)

是用于 调用 代码的。考虑以下调用:

foo("a", "b");

对于foo的第一次声明而言,这是有效的,编译器将生成代码,在执行时创建一个包含对"a""b"引用的数组。然而,对于foo的第二次声明,这是无效的,因为它没有使用可变参数。

在任何情况下,调用者可以明确地创建该数组:

for(new String[] { "a", "b" }); // Valid for either declaration
当它写成main(String[] args)时,它不使用可变参数;如果您将其写为main(String... args),则使用可变参数。然而,这与JVM如何处理它无关,因为JVM初始化会创建一个带有命令行参数的数组。只有在编写自己的代码显式调用main时才会有所区别。

1
你也可以不带参数调用它。 - wvdz
@popovitsj:是的,尽管这将最终创建一个空数组。 - Jon Skeet
1
你可以使用长度为0的数组调用第二种形式,但这需要更多的打字努力 :) - laune
1
@DroidIcs:这其实就是同一件事情——只不过“你指定数组中想要的元素,而不是显式地创建数组”。 - Jon Skeet
1
还有一个区别:可变参数必须是方法的最后一个参数。 - Andrew Tobilko
显示剩余2条评论

5
我们可以使用数组代替可变参数。可变参数只是使用数组的语法糖。但它们可以使您的代码更加简洁和易读。比较一下:
private void foo(String... ss) { ... }

private void bar() {
    ...
    foo("One", "Two", "Three");
    ...
}

使用

private void foo(String[] ss) { ... }

private bar() {
    ...
    foo(new String[] { "One", "Two", "Three" });
    ...
}

同样地,我们并不需要钻石操作符(<>,Java 7)或者Lambda表达式(Java 8)。但是它们确实让代码更容易阅读,因此更易于维护。

4

可变参数的一个优点是对于需要至少一个参数的方法,例如max。使用可变参数,您可以像这样实现:

static int max(int first, int... remaining) {
    int max = first;
    for (int number : remaining)
        max = Math.max(max, number);
    return max;
}

这很好,因为不可能对max方法不传参数,调用max的代码非常简洁:max(2, 4, 1, 8, 9)。没有可变参数,在确保至少传递一个数字的条件下,唯一的方法是在运行时抛出异常(最好避免)或强制调用者编写max(2, new int[] {4, 1, 8, 9}),这真的很丑陋。

2

因为您的函数调用看起来更像一个函数调用,例如:

new MyAsyncTask().execute("str1", "str2");

比起这个更好看:

new MyAsyncTask().execute(new String[]{"str1", "str2"});
AsyncTask并没有什么神奇的地方,很多时候你其实不需要传递任何参数,有时候你会在构造函数中传递参数而不是执行。还有一些AsyncTask的实现,例如:https://github.com/roboguice/roboguice/blob/master/roboguice/src/main/java/roboguice/util/SafeAsyncTask.java,完全不使用可变参数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接