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


275

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

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

这里的问题是,在方法中将其args视为,因此是的单个参数,而我希望将每个in 作为新参数传递。由于也是带有可变参数的方法,因此应该可行。Object[]myFormatString.formatObjectargsString.format

如果这不可能,是否有类似的方法String.format(String format, Object[] args)?在这种情况下,我可以在前面加上extraVarargs使用新的数组,并把它传递给该方法。


8
我不禁想知道为什么这个问题是“这种有效的”问题。您不能尝试一下吗?不要过度提问,弊大于利。
kamasheto

21
的确如此,这本可以很容易地进行测试。但是,关于这样的问题的好处是,它公开了主题并征集了有趣的答案。
akf 2010年

2
我实际上尝试了上面的代码,目的是将数组args作为参数传递给方法。但是,我没有意识到我应该先将extraVar放在args之前。当您知道变量参数被视为数组(甚至在方法之外)时,这当然是很合逻辑的。
user362382'5

Answers:


180

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

因此,您应该只可以挂接extraVarargs并致电String.format(format, args)


在Eclipse中将类型的参数传递X[]给方法x(X... xs)会给出以下警告:Type X[] of the last argument to method x(X...) doesn't exactly match the vararg parameter type. Cast to X[] to confirm the non-varargs invocation, or pass individual arguments of type X for a varargs invocation.
Luke Hutchison

318

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

JLS 8.4.1格式参数

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

如果最后一个形式参数是类型的可变arity参数T,则考虑定义类型的形式参数T[]。该方法则是可变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...是just String[]。另外,由于数组是协变String[]Object[],所以a 是一个,因此您也可以ezFormat(args)使用任何一种方式进行调用。

也可以看看


Varargs陷阱#1:传递 null

可变参数的解析非常复杂,有时它会使您感到惊讶。

考虑以下示例:

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!!!

由于可变参数是如何解决的,最后一条语句调用与objs = null,这当然会导致NullPointerExceptionobjs.length。如果要将一个null参数赋予varargs参数,则可以执行以下任一操作:

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个参数,第一个是a String[],第二个是a 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 ]"

2
使用对象...可变参数使得难以使用其他签名,因为编译器会识别签名之间的歧义,即使是原始参数也可以自动装箱到对象。
eel ghEEz 2015年

7
缺少一个陷阱:如果您的方法的最后一个参数的类型为Object ...,并且您通过例如String []来调用它。编译器不知道您的数组是varargs的第一项还是等同于所有varargs。它会警告您。
Snicolas

在Eclipse中将类型的参数传递X[]给方法x(X... xs)会给出以下警告:Type X[] of the last argument to method x(X...) doesn't exactly match the vararg parameter type. Cast to X[] to confirm the non-varargs invocation, or pass individual arguments of type X for a varargs invocation.
Luke Hutchison

23

可以通过数组-实际上,它等同于同一件事

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

是相同的

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

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

看到


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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.