Могу ли я передать массив в качестве аргументов метода с переменными аргументами в Java?

Я бы хотел создать такую ​​функцию, как:

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

Проблема заключается в том, что args рассматривается как Object[] в методе myFormat и, следовательно, является единственным аргументом для String.format, тогда как я хотел бы, чтобы каждый Object в args в качестве нового аргумента. Поскольку String.format также является методом с переменными аргументами, это должно быть возможно.

Если это невозможно, существует ли метод, например String.format(String format, Object[] args)? В этом случае я мог бы добавить extraVar в args с помощью нового массива и передать его этому методу.

Ответ 1

Основной тип вариационного метода function(Object... args) - function(Object[] args). Sun добавила varargs таким образом, чтобы сохранить обратную совместимость.

Итак, вы должны просто добавить extraVar в args и вызвать String.format(format, args).

Ответ 2

Да, a T... является только синтаксическим сахаром для T[].

JLS 8.4.1 Параметры формата

Последний формальный параметр в списке является особым; он может быть переменным параметром arity, обозначенным elipsis, следующим за типом.

Если последний формальный параметр является параметром переменной arty типа T, считается, что он определяет формальный параметр типа T[]. Затем метод является методом переменной arity. В противном случае это фиксированный метод 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[]. Кроме того, поскольку массивы ковариантны, a String[] является Object[], поэтому вы также можете вызвать ezFormat(args) в любом случае.

См. также


Varargs gotchas # 1: передача 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. Если вы хотите дать один аргумент null параметру varargs, вы можете выполнить одно из следующих действий:

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

Связанные вопросы

Ниже приведен пример некоторых вопросов, которые люди задавали при работе с varargs:


Vararg gotchas # 2: добавление дополнительных аргументов

Как вы узнали, следующее "не работает":

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

Из-за того, как работают varargs, 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 gotchas # 3: передача массива примитивов

Он не работает:

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

Varargs работает только со ссылочными типами. Автобоксинг не применяется к массиву примитивов. Следующие работы:

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

Ответ 3

Хорошо передать массив - на самом деле это то же самое.

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

совпадает с

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

Это просто синтаксический сахар - компилятор преобразует первый во второй, так как базовый метод ожидает массив для vararg параметр.

См

Ответ 4

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

Ответ 5

У меня была такая же проблема.

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

И затем передал obj как аргумент varargs. Это сработало.