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

2024-01-10

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

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

这里的问题是args被视为Object[]在方法中myFormat,因此是一个参数String.format,虽然我想要每一个Object in args作为新参数传递。自从String.format也是一个带有可变参数的方法,这应该是可能的。

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


Yes, a T...只是一个语法糖T[].

JLS 8.4.1 格式参数 https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#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[] is an Object[],所以你也可以打电话ezFormat(args)无论哪种方式。

See also

  • Java 语言指南/varargs http://java.sun.com/j2se/1.5.0/docs/guide/language/varargs.html

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

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

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

相关问题

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

  • 可变参数和重载的错误? https://stackoverflow.com/questions/2521293/bug-with-varargs-and-overloading
  • 如何使用可变参数和反射 https://stackoverflow.com/questions/2600854/how-to-work-with-varargs-and-reflection
  • 与固定/可变数量(可变参数)匹配的最具体方法 https://stackoverflow.com/questions/1321657/most-specific-method-with-matches-of-both-fixed-variable-arity-varargs

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

正如您所发现的,以下内容不起作用:

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

由于可变参数的工作方式,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 ]"
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐