Я хотел бы смочь создать функцию как:
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
использование нового массива и передачи это к тому методу.
Базовый тип вариативного метода function(Object... args)
is function(Object[] args)
. Sun добавила varargs таким образом, чтобы сохранить обратную совместимость.
Поэтому вы должны быть в состоянии просто добавить extraVar
к args
и вызвать String.format(format, args)
.
Передавать массив - это нормально - на самом деле это то же самое
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);
Да, T...
- это только синтаксический сахар для T[]
.
Последний формальный параметр в списке является специальным; он может быть параметром переменной степени сложности, на что указывает элипсис после типа.
Если последний формальный параметр является параметром переменной четкости типа
T
, то считается, что он определяет формальный параметр типаT[]
. Тогда метод является методом переменной четкости. В противном случае это метод фиксированной четкости. Вызовы метода переменной четкости могут содержать больше фактических выражений аргументов, чем формальных параметров. Все фактические выражения аргументов, которые не соответствуют формальным параметрам, предшествующим параметру переменной четкости, будут оценены и результаты сохранены в массив, который будет передан в вызов метода.
Вот пример для иллюстрации:
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)
в любом случае.
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!!!
Из-за того, как разрешаются варарги, последнее утверждение вызывает objs = null
, что, конечно, вызовет NullPointerException
с objs.length
. Если вы хотите передать один null
аргумент параметру varargs, вы можете сделать одно из следующих действий:
count(new Object[] { null }); // prints "1"
count((Object) null); // prints "1"
Ниже приведена выборка некоторых вопросов, которые люди задавали при работе с varargs:
Как вы уже выяснили, следующее не "работает":
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 ]"
Это не "работает":
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 ]"