Список параметров метода Java varags и массив
С varargs:
public static void foo(String... string_array) { ... }
и
одиночный массив param:
public static void bar(String[] string_array) { ... }
Java 1.6, похоже, принимает/отклоняет следующее:
String[] arr = {"abc", "def", "ghi"};
foo(arr); // accept
bar(arr); // accept
foo("abc", "def", "ghi"); // accept
bar("abc", "def", "ghi"); // reject
предполагая, что выше указано true / correct, почему бы не всегда использовать varargs вместо одного массива param? Кажется, добавить прикосновение вызывающего абонента flexiblity бесплатно.
может ли эксперт разделить внутреннюю разницу JVM, если она есть?
спасибо.
6 ответов
массивы были вокруг с самого начала Java, в то время как varargs являются довольно недавним дополнением. Таким образом, многие старые коды по-прежнему с удовольствием используют массивы.
обратите внимание также, что вызов универсального метода vararg с явным параметром массива может тихо привести к другому поведению, чем ожидалось:
public <T> void foo(T... params) { ... }
int[] arr = {1, 2, 3};
foo(arr); // passes an int[][] array containing a single int[] element
таким образом-помимо необходимости больших усилий без явной выгоды-не всегда желательно заменять устаревшие параметры массива на с varargs.
не говоря уже о случаях, когда вы не можете, потому что есть еще один параметр после выбора в списке параметров метода:
public void foo(String[] strings, String anotherParam) { ... }
переупорядочивание параметров может технически решить эту проблему, однако это нарушает клиентский код.
обновление: эффективная Java 2nd. Издание, Пункт 42: используйте varargs разумно объясняет это более подробно, приводя также конкретный пример:Arrays.asList()
был модернизирован в Java5, чтобы иметь vararg параметры, которые непреднамеренно сломал много существующего кода может вызвать сюрпризы при использовании этой (теперь устаревшей) идиомы для печати массива:
System.out.println(Arrays.asList(myArray));
обновление 2: проверил источник, и он говорит, что проблема возникает с массивами примитивных типов данных, таких как int[]
. Перед varargs, код, как это:
int[] digits = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };
System.out.println(Arrays.asList(digits));
выдаст ошибку компиляции, потому что только массивы ссылочных типов могут быть преобразованы в List
. С с varargs, и переоборудование asList
, код выше компилируется без предупреждений, а непреднамеренный результат-что-то вроде "[[I@3e25a5]"
.
основная причина не указывать все как varargs заключается в том, что это не всегда имеет смысл. Например, если InputStream.read(byte[])
где определено как ' read (byte...) тогда действителен следующий вызов:
myInputStream.read(0, 1, 2, 3);
это создаст 4-элементный байтовый массив, передаст его и затем отбросит.
vararg-это простой синтаксический сахар для массива.
если вы называете foo("abc", "def", "ghi");
затем
компилятор назовет его foo(new String[] {"abc", "def", "ghi"});
компилятор создаст один новый массив и передаст его в foo()
.
Нельзя иметь и то, и другое!--3--> и foo(String[])
. Поскольку оба функционально одинаковы.
в foo вы указываете три параметра, вы должны были бы позвонить в бар, как это:
bar(new String[]{"abc", "def", "ghi"});
Так что вы вызываете его только с одним параметром, то есть строкой[] в этом случае это не имеет ничего общего с внутренними, ваша подпись метода для панели методов просто утверждает, что она имеет только один параметр, тогда как foo имеет n параметров, которые являются строками
Это, как определяются varargs. Расширение с varargs не каждый акцептная функция блока функция с varargs. Вы должны позвонить в бар так:
bar(new String[]{"abc", "def", "ghi"})
другое отличие-эффективность. Объекты, находящиеся внутри явного массива, не будут вызываться. Однако параметры списка аргументов переменных вычисляются при нажатии метода в стеке.
Это очевидно, когда вызов функции передается в качестве параметра, возвращающего тип, используемый в списке аргументов переменных.
пример: метода someMethod( объект... икс) anotherMethod (Object []);
someMethod (a (), b (), c ()); / / a, b и c будет вызван, прежде чем вы попадете в метод.
anotherMethod (new Object[]{a (), b (), c ()}); / / методы не вызываются, пока объекты не будут доступны.