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

时间:2010-05-27 21:36:39

标签: java arrays backwards-compatibility variadic-functions

我希望能够创建一个类似的函数:

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

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

如果无法做到这一点,是否有类似String.format(String format, Object[] args)的方法?在这种情况下,我可以使用新数组将extraVar添加到args并将其传递给该方法。

5 个答案:

答案 0 :(得分:288)

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

JLS 8.4.1 Format parameters

  

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

     

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

以下是一个例子来说明:

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)

另见


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

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

相关问题

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


Vararg陷阱#2:添加额外的参数

正如您所知,以下内容并非“有效”:

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

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

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

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陷阱#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 ]"

答案 1 :(得分:160)

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

因此,您应该能够将extraVar添加到args并致电String.format(format, args)

答案 2 :(得分:21)

传递一个数组是可以的 - 实际上它相同的东西

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

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

这只是语法糖 - 编译器将第一个转换为第二个,因为底层方法期望vararg参数的数组。

答案 3 :(得分:4)

jasonmp85关于将不同的数组传递给String.format是正确的。一旦构造,数组的大小就无法更改,因此您必须传递一个新数组而不是修改现有数组。

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

答案 4 :(得分:1)

我遇到了同样的问题。

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

然后通过obj作为varargs参数。 它奏效了。