Список параметров var var var vs. array

Varargs:

public static void foo(String... string_array) { ... }

против

Параметр одиночного массива:

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

Предполагая, что приведенное выше верно/правильно, почему не всегда использовать varargs вместо параметра single array? Кажется, что бесплатно добавьте гибкость звонящего.

Может ли эксперт делиться внутренней разницей 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
</t>

Таким образом - помимо требующих больших усилий без явной выгоды - не всегда желательно заменять устаревшие параметры массива на varargs.

Не говоря уже о случаях, когда вы не можете, потому что в списке параметров метода есть еще один параметр:

public void foo(String[] strings, String anotherParam) { ... }

Переупорядочение параметров может технически решить эту проблему, однако оно нарушает клиентский код.

Обновление: Эффективная Java 2nd. Издание, пункт 42: Использование varargs разумно объясняет это более подробно, давая также конкретный пример: Arrays.asList() был модифицирован в Java5, чтобы иметь параметры vararg, которые случайно побила много существующего кода, может вызвать неожиданности при использовании этой (теперь устаревшей) идиомы для печати массива:

System.out.println(Arrays.asList(myArray));

Update2: Двойной проверил источник, и он говорит, что проблема возникает с массивами примитивных типов, например 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...), тогда будет выполнен следующий вызов:

*************.read(0, 1, 2, 3);

Это создало бы 4-элементный массив байтов, передал бы его и отменил бы его.


vararg - простой синтаксический сахар для массива.

если вы вызываете foo("abc", "def", "ghi");, тогда компилятор будет называть его foo(new String[] {"abc", "def", "ghi"});

компилятор создаст один новый массив и передаст его в foo(). Нельзя иметь как foo(String...), так и foo(String[]). Поскольку оба функционально одинаковы.


Это то, как определяются varargs. Расширение varargs не делает каждый массив, принимающий функцию, функцией varargs. Вы должны вызвать бар следующим образом:

bar(new String[]{"abc", "def", "ghi"})


в foo вы указываете три параметра, вам нужно будет вызвать бар следующим образом:

bar(new String[]{"abc", "def", "ghi"});

так что вы вызываете его только одним параметром, то есть строкой [] в этом случае это не имеет ничего общего с внутренними, ваша сигнатура метода для панели методов просто утверждает, что она имеет только один параметр, тогда как foo имеет n параметров, которые являются всеми строками


Еще одно отличие - эффективность. Объекты, находящиеся внутри явного массива, не будут вызваны. Однако параметры списка переменных аргументов вычисляются, когда метод помещается в стек.

Это видно, когда вызов функции передается как параметр, который возвращает тип, который используется в списке аргументов переменных.

Пример: someMethod (Object... x) anotherMethod (Object []);

someMethod (a(), b(), c());//a, b и c будут вызваны, прежде чем вы войдете в метод.

anotherMethod (новый объект [] {a(), b(), c()});//Эти методы не вызываются до тех пор, пока не будут доступны объекты.

licensed under cc by-sa 3.0 with attribution.