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

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

这里的问题是,args在myFormat方法中被视为Object[],因此是String的单个参数。格式,而我想每一个单独的对象在args传递作为一个新的参数。因为字符串。Format也是一个带有变量参数的方法,这应该是可能的。

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


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

你应该能够将extraVar前置到args并调用String。格式(格式,args)。


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

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

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

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

See

可变参数- J2SE 1.5文档


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格式参数

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.

这里有一个例子来说明:

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[]。此外,因为数组是协变的,字符串[]是对象[],所以你也可以用任何一种方式调用ezFormat(args)。

另请参阅

Java语言指南/变量参数


变参数陷阱#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,这当然会导致objs.length的NullPointerException。如果你想给varargs形参一个空参数,你可以做以下任何一种:

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

相关问题

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

Bug与可变参数和重载? 如何使用可变参数和反射 最具体的方法与固定/可变的匹配(varargs)


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

正如你所发现的,下面的方法是行不通的:

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

由于可变参数的工作方式,ezFormat实际上得到2个参数,第一个是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参数传递。 它工作。