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

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

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

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

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

273528 次浏览

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

所以你应该能够将extraVar前置到args并调用String.format(format, args)

传递一个数组是可以的——事实上,它们是一样的

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

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

这只是语法糖——编译器将第一个转换为第二个,因为底层方法期望可变长度形参的数组。

看到

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

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

JLS 8.4.1格式参数

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

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

这里有一个例子来说明:

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)

另请参阅


可变参数问题#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!!!

由于varargs是如何解析的,最后一个语句调用objs = null,这当然会导致NullPointerExceptionobjs.length。如果你想给varargs形参一个null参数,你可以做以下任何一种:

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

相关问题

下面是一些人们在处理变参数时问过的问题:


变参数陷阱#2:添加额外参数

正如你所发现的,下面的方法并不“有效”:

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

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

下面是一些有用的helper方法:

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

变参数陷阱#3:传递一个原语数组

它并不“有效”:

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

可变参数只适用于引用类型。自动装箱不适用于原语数组。以下工作:

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

我也有同样的问题。

String[] arr= new String[] { "A", "B", "C" };
Object obj = arr;
然后将obj作为varargs参数传递。 它工作。< / p >