Вопрос-ответ

Can I pass an array as arguments to a method with variable arguments in Java?

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

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

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


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


Если последний формальный параметр является параметром переменной арности типа T, считается, что он определяет формальный параметр типа 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[]. Кроме того, поскольку массивы ковариантны, a String[] является 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, что, конечно, вызвало бы NullPointerException with objs.length. Если вы хотите предоставить один null аргумент параметру varargs, вы можете выполнить любое из следующих действий:

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

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

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


Vararg gotchas #2: adding extra arguments

As you've found out, the following doesn't "work":

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

Because of the way varargs work, ezFormat actually gets 2 arguments, the first being a String[], the second being a String. If you're passing an array to varargs, and you want its elements to be recognized as individual arguments, and you also need to add an extra argument, then you have no choice but to create another array that accommodates the extra element.

Here are some useful helper methods:

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

Now you can do the following:

    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: passing an array of primitives

It doesn't "work":

    int[] myNumbers = { 1, 2, 3 };
System.out.println(ezFormat(myNumbers));
// prints "[ [I@13c5982 ]"

Varargs only works with reference types. Autoboxing does not apply to array of primitives. The following works:

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

The underlying type of a variadic method function(Object... args) is function(Object[] args). Sun added varargs in this manner to preserve backwards compatibility.

So you should just be able to prepend extraVar to args and call String.format(format, args).

Ответ 3

It's ok to pass an array - in fact it amounts to the same thing

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

is the same as

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

It's just syntactic sugar - the compiler converts the first one into the second, since the underlying method is expecting an array for the vararg parameter.

See

Ответ 4

jasonmp85 is right about passing a different array to String.format. The size of an array can't be changed once constructed, so you'd have to pass a new array instead of modifying the existing one.

Object newArgs = new Object[args.length+1];
System.arraycopy(args, 0, newArgs, 1, args.length);
newArgs[0] = extraVar;
String.format(format, extraVar, args);
java arrays