Могу ли я передать массив в качестве аргументов методу с переменными аргументами в 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 используя новый массив и передайте его этому методу.

5 ответов


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

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


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

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

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

если последний формальный параметр является переменным параметром arity типа T, считается определить формальный параметр типа T[]. Метод тогда a переменная arity метод. В противном случае, это исправлено arity метод. Вызовы метода переменной arity могут содержать больше фактических выражений аргументов, чем формальных параметров. Все фактические выражения аргументов, не соответствующие формальным параметрам, предшествующим параметру переменной arity, будут оценены, а результаты сохранены в массиве, который будет передан вызову метода.

вот пример проиллюстрировать:

public static String ezFormat(Object... args) {
    String format = new String(new char[args.length])
        .replace("", "[ %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 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 "[ [I@13c5982 ]"

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

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

это нормально, чтобы передать массив-на самом деле это то же самое

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

это то же самое, что

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

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

посмотреть


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

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

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

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