Могу ли я передать массив в качестве аргументов методу с переменными аргументами в 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:
- bug with varargs and overloading?
- How to work with varargs and reflection
- Most specific method with matches of both fixed/variable arity (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);