我可以将数组作为参数传递给Java中带有变量参数的方法吗?

Can I pass an array as arguments to a method with variable arguments in Java?

我希望能够创建如下函数:

1
2
3
4
5
6
class A {
  private String extraVar;
  public String myFormat(String format, Object ... args){
    return String.format(format, extraVar, args);
  }
}

这里的问题是,在方法myFormat中,args被视为Object[],因此是String.format的单一论点,而我希望args中的每一个Object都作为新论点传递。由于String.format也是一种带有可变参数的方法,因此这应该是可能的。

如果这是不可能的,有没有像String.format(String format, Object[] args)这样的方法?在这种情况下,我可以使用一个新的数组将extraVar提前发送到args,并将其传递给该方法。


是的,一个T...只是一个T[]的语法糖。

JLS 8.4.1格式参数

The last formal parameter in a list is special; it may be a variable arity parameter, indicated by an elipsis following the type.

If the last formal parameter is a variable arity parameter of type T, it is considered to define a formal parameter of type T[]. The method is then a variable arity method. Otherwise, it is a fixed arity method. Invocations of a variable arity method may contain more actual argument expressions than formal parameters. All the actual argument expressions that do not correspond to the formal parameters preceding the variable arity parameter will be evaluated and the results stored into an array that will be passed to the method invocation.

下面是一个例子来说明:

1
2
3
4
5
6
7
8
9
public static String ezFormat(Object... args) {
    String format = new String(new char[args.length])
        .replace("\0","[ %s ]");
    return String.format(format, args);
}
public static void main(String... args) {
    System.out.println(ezFormat("A","B","C"));
    // prints"[ A ][ B ][ C ]"
}

是的,上述的main方法是有效的,因为同样,String...只是String[]方法。另外,因为数组是协变的,所以String[]Object[],所以您也可以以任何方式调用ezFormat(args)

也见

  • Java语言指南/ VARARGS

varargs gotchas 1:通过null

如何解决varargs是相当复杂的,有时它做的事情可能会让你吃惊。

考虑这个例子:

1
2
3
4
5
6
7
static void count(Object... objs) {
    System.out.println(objs.length);
}

count(null, null, null); // prints"3"
count(null, null); // prints"2"
count(null); // throws java.lang.NullPointerException!!!

由于varargs是如何解决的,最后一个语句调用objs = null,这当然会导致NullPointerException调用objs.length。如果要为varargs参数提供一个null参数,可以执行以下任一操作:

1
2
count(new Object[] { null }); // prints"1"
count((Object) null); // prints"1"

相关问题

以下是人们在处理varargs时提出的一些问题的示例:

  • varargs和重载的bug?
  • 如何处理varargs和反射
  • 具有固定/变量arity(varargs)匹配项的最具体方法

vararg gotchas 2:添加额外参数

正如您所发现的,以下内容不"有效":

1
2
3
    String[] myArgs = {"A","B","C" };
    System.out.println(ezFormat(myArgs,"Z"));
    // prints"[ [Ljava.lang.String;@13c5982 ][ Z ]"

由于varargs的工作方式,ezFormat实际上有两个参数,第一个是String[],第二个是String。如果要将数组传递给varargs,并且希望将其元素识别为单个参数,并且还需要添加一个额外的参数,那么除了创建容纳额外元素的另一个数组之外,您别无选择。

以下是一些有用的助手方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
static <T> T[] append(T[] arr, T lastElement) {
    final int N = arr.length;
    arr = java.util.Arrays.copyOf(arr, N+1);
    arr[N] = lastElement;
    return arr;
}
static <T> T[] prepend(T[] arr, T firstElement) {
    final int N = arr.length;
    arr = java.util.Arrays.copyOf(arr, N+1);
    System.arraycopy(arr, 0, arr, 1, N);
    arr[0] = firstElement;
    return arr;
}

现在您可以执行以下操作:

1
2
3
4
5
6
    String[] myArgs = {"A","B","C" };
    System.out.println(ezFormat(append(myArgs,"Z")));
    // prints"[ A ][ B ][ C ][ Z ]"

    System.out.println(ezFormat(prepend(myArgs,"Z")));
    // prints"[ Z ][ A ][ B ][ C ]"

varargs gotchas 3:传递基元数组

它不起作用:

1
2
3
    int[] myNumbers = { 1, 2, 3 };
    System.out.println(ezFormat(myNumbers));
    // prints"[ [I@13c5982 ]"

varargs只能用于引用类型。自动修改不适用于基元数组。以下工作:

1
2
3
    Integer[] myNumbers = { 1, 2, 3 };
    System.out.println(ezFormat(myNumbers));
    // prints"[ 1 ][ 2 ][ 3 ]"


可变方法function(Object... args)的基础类型是function(Object[] args)。Sun以这种方式添加varargs以保持向后兼容性。

所以你只需要提前把extraVar交给args并打电话给String.format(format, args)


传递一个数组是可以的-事实上,它等于

1
String.format("%s %s","hello","world!");

是一样的

1
String.format("%s %s", new Object[] {"hello","world!"});

这只是语法上的甜头——编译器将第一个转换为第二个,因为底层方法需要vararg参数的数组。

  • varargs-J2SE 1.5文档

jasonmp85向String.format传递不同的数组是正确的。数组的大小在构造后不能更改,因此您必须传递一个新的数组,而不是修改现有的数组。

1
2
3
4
Object newArgs = new Object[args.length+1];
System.arraycopy(args, 0, newArgs, 1, args.length);
newArgs[0] = extraVar;
String.format(format, extraVar, args);

我也有同样的问题。

1
2
String[] arr= new String[] {"A","B","C" };
Object obj = arr;

然后将obj作为varargs参数传递。它奏效了。