Список параметров метода 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 ()}); / / методы не вызываются, пока объекты не будут доступны.