324

我希望能够创建一个函数,如:

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

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

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

4

5 回答 5

352

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

JLS 8.4.1 格式参数

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

如果最后一个形参是类型的可变参数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...String[]. 另外,因为数组是协变的,所以 aString[]是 an Object[],所以你也可以调用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!!!

由于可变参数的解析方式,最后一条语句调用 with objs = null,这当然会导致NullPointerExceptionwith objs.length。如果您想为nullvarargs 参数提供一个参数,您可以执行以下任一操作:

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

相关问题

以下是人们在处理可变参数时提出的一些问题的示例:


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。如果您将一个数组传递给可变参数,并且您希望其元素被识别为单独的参数,并且您还需要添加一个额外的参数,那么您别无选择,只能创建另一个容纳额外元素的数组。

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

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 ]"
于 2010-05-28T04:32:09.257 回答
203

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

因此,您应该能够预先extraVar设置args并调用String.format(format, args).

于 2010-05-27T21:58:41.480 回答
25

传递一个数组是可以的 - 实际上它相当于同一件事

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

是相同的

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

它只是语法糖——编译器将第一个转换为第二个,因为底层方法需要一个可变参数参数的数组。

于 2010-05-27T22:00:28.030 回答
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);
于 2010-05-28T04:19:43.363 回答
3

我遇到了同样的问题。

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

然后将 obj 作为可变参数传递。有效。

于 2017-12-19T13:52:42.703 回答