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

dkqlctbz  于 2023-05-05  发布在  Java
关注(0)|答案(6)|浏览(276)

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

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,并将其传递给该方法。

wswtfjt7

wswtfjt71#

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

JLS 8.4.1格式参数

列表中的最后一个形参是特殊的;它可以是 variable arity 参数,由type后面的省略号指示。
如果最后一个形式参数是T类型的变量arity参数,则认为定义了T[]类型的形式参数。因此,该方法是一个 * 变量 * 方法。否则,它是一个 * 固定参数 * 方法。变量方法的调用可以包含比形参更多的实际实参表达式。所有与变量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[]。此外,因为数组是协变的,所以String[]Object[],所以您也可以以任何方式调用ezFormat(args)

参见

Varargs得到了一个:通过null

如何解析varargs是相当复杂的,有时它会做一些让您感到惊讶的事情。
请考虑以下示例:

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调用,这当然会导致NullPointerException使用objs.length。如果你想给予一个varargs参数一个null参数,你可以执行以下任一操作:

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实际上有两个参数,第一个是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 ]"

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

fgw7neuy2#

variadic方法function(Object... args) * 的底层类型是 * function(Object[] args)。Sun以这种方式添加了varargs以保持向后兼容性。
因此,您应该能够将extraVar前置到args并调用String.format(format, args)

gajydyqb

gajydyqb3#

传递一个数组是可以的--实际上它的作用是一样的

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

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

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

hmmo2u0o

hmmo2u0o4#

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

gmxoilav5#

我也有同样的问题。

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

然后将obj作为varargs参数传递。成功了

au9on6nz

au9on6nz6#

除了@genelubricant的#2之外-如果只读就足够了,如果你想交换一点额外的努力来获得List的一些便利-复制数组并 Package 它并不一定需要,加上在访问时在任意索引处注入所需的额外值,可以像这样实现:

public static <T> List<Object> wrappedUnmodfiableListInsertion(final T insert, final Integer insertIdx, final T... source) {
  final boolean isInsertion = insertIdx != null;
  return new AbstractList<Object>() {
    @Override
    public int size() {
      return source != null ? isInsertion ? source.length + 1 : source.length : 0;
    }
    @Override
    public Object get(int index) {
      if (source == null) {
        if (isInsertion) {
          return index == insertIdx && index == 0 ? insert : null;
        }
        return EMPTY_LIST;
      } 
      if (isInsertion) {
        if (index == insertIdx) {
          return insert;
        } 
        return source[insertIdx > index ? index : index - 1];
      }
      return source[index];
    }
  };
}

相关问题