是否可以将数组作为参数传递给 Java 中具有变量参数的方法?

我希望能够创建一个这样的函数:

class A {
  private String extraVar;
  public String myFormat(String format, Object ... args){
    return String.format(format, extraVar, args);
  }
}

这里的问题是,它被当作方法,因此是一个单一的参数,而我希望每个参数都作为一个新的参数传递。由于也是具有变量参数的方法,因此这应该是可能的。argsObject[]myFormatString.formatObjectargsString.format

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


答案 1

是的,a 只是 a 的句法糖。T...T[]

JLS 8.4.1 格式参数

列表中的最后一个正式参数是特殊的;它可以是一个可变的 arity 参数,由类型后面的省略号指示。

如果最后一个形式参数是类型的变量 arity 参数,则认为它定义了类型的形式参数。然后,该方法是可变 arity 方法。否则,它是一种固定的 arity 方法。与形式参数相比,变量 arity 方法的调用可能包含更多的实际参数表达式。将计算与变量 arity 参数前面的形式参数不对应的所有实际参数表达式,并将结果存储到将传递给方法调用的数组中。TT[]

下面是一个示例来说明:

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 ]"
}

是的,上述方法是有效的,因为同样,只是 .此外,由于数组是协变的,因此 a 是 一个 ,因此您也可以以任何一种方式调用。mainString...String[]String[]Object[]ezFormat(args)

另请参见


瓦拉格斯得到#1:传球null

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

请考虑以下示例:

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 的解析方式,最后一个语句调用 with ,这当然会导致 。如果要为 varargs 参数提供一个参数,可以执行以下任一操作:objs = nullNullPointerExceptionobjs.lengthnull

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

相关问题

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


Vararg gotchas #2:添加额外的参数

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

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

由于 varargs 的工作方式,实际上得到 2 个参数,第一个是 a,第二个是 。如果要将数组传递给 varargs,并且希望将其元素识别为单个参数,并且还需要添加一个额外的参数,则您别无选择,只能创建另一个容纳额外元素的数组。ezFormatString[]String

以下是一些有用的帮助程序方法:

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;
}

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

    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:传递一个基元数组

它不“工作”:

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

Varargs 仅适用于引用类型。自动装箱不适用于基元数组。以下工作原理:

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

答案 2

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

因此,您应该能够预先附加到 并调用 .extraVarargsString.format(format, args)