Разница между double ... и double [] в формальном объявлении типа параметра - PullRequest
2 голосов
/ 22 мая 2010

У меня вопрос: в чем разница между этими двумя декларациями?

 public static void printMax(double... numbers) { ... }

 public static void printmax(double numbers[])  { ... }

Является ли double... numbers таким же, как double numbers[]?

Ответы [ 3 ]

8 голосов
/ 22 мая 2010

На варагс

Конструкция Type... в объявлении параметров метода обычно называется varargs. В JLS это называется параметром переменная arity .

JLS 8.4.1 Параметры формата

Последний формальный параметр в списке является специальным; это может быть переменная arity параметр, обозначенный elipsis после типа.

Если последний формальный параметр является параметром переменной arity типа T, считается, что он определяет формальный параметр типа T[]. Метод тогда является переменная arity метод. В противном случае это метод fixed arity . Вызовы метода переменной арности могут содержать больше фактических выражений аргументов, чем формальных параметров. Все действительные выражения аргумента, которые не соответствуют формальным параметрам, предшествующим параметру переменной arity, будут оценены, а результаты сохранены в массив, который будет передан в вызов метода.

Чтобы проиллюстрировать в коде, вот что varargs позволяет вам делать:

static void f(int... nums) {
    for (int num : nums) {
        System.out.println(num);
    }
}
//...

f(1,2,3); // prints "1", "2", "3"

Напротив, без конструкции varargs вы должны сделать это:

static void g(int[] nums) {
    for (int num : nums) {
        System.out.println(num);
    }       
}
//...

g(new int[] { 1, 2, 3 }); // prints "1", "2", "3"

Varargs - это то, что называется синтаксическим сахаром, который скрывает от вас многословие.

Итак, чтобы вернуться к вашему вопросу, разница между printMax(double... numbers) и printmax(double numbers[]) заключается в том, что первым является метод variable arity , то есть вы можете присвоить ему переменное количество параметров. Последний - это метод fixed arity , что означает, что он будет принимать один-единственный параметр.

Обратите внимание на приведенную выше цитату о том, что T... действительно T[]. То есть даже с varargs вы можете делать следующее:

f(new int[] { 1, 2, 3 }); // prints "1", "2", "3"

Здесь вы вручную создаете массив для хранения параметров vararg. На самом деле, если вы зайдете так далеко, как декомпилируете код, вы обнаружите, что, как указано в JLS, f фактически принимает параметр int[], а f(1, 2, 3) реализован как f(new int[] { 1, 2, 3 }).

См. Также


Varargs Gotchas

Как решить 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!!!

Из-за того, как решаются varargs, последний оператор вызывается с objs = null, что, конечно, приведет к NullPointerException с objs.length. Если вы хотите дать один null аргумент параметру varargs, вы можете сделать одно из следующих:

count(new Object[] { null }); // prints "1"
count((Object) null); // prints "1"

Похожие вопросы

Ниже приведен пример некоторых вопросов, которые люди задавали при работе с varargs:


Когда использовать varargs

Как показал предыдущий раздел, varargs может быть хитрым. Однако при правильном использовании они могут привести к гораздо более лаконичному коду.

Вот цитата из Effective Java 2nd Edition, Item 42: Используйте varargs разумно (выделено автором):

Урок понятен. Не модифицируйте каждый метод, имеющий окончательный параметр массива; используйте varargs только , когда вызов действительно работает с последовательностью значений переменной длины .

Варарги могут не только сбивать с толку, но и дорого обходиться. Effective Java 2nd Edition фактически рекомендует предоставлять перегрузки фиксированной арности для наиболее распространенных сценариев использования.

Предположим, вы определили, что 95 процентов вызовов метода имеют три или менее параметров. Затем объявите пять перегрузок метода, по одному для каждого с нулем через три обычных параметра, и один varargs для использования, когда число параметров превышает три.

Книга идет гораздо глубже, но по сути вы должны использовать varargs только тогда, когда это действительно имеет смысл.И даже в этих случаях вы все равно можете подумать о предоставлении перегрузок с фиксированной арностью для повышения производительности.

Смежный вопрос

API ссылки

Вот несколько примеров, где varargs имеет смысл:


При объявлении массива

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

int x[];

Вместо скобок следует ставить тип , а не идентификатор :

int[] x;

Обратите внимание, что это также относится к массивам в приведенных выше обсуждениях, например, T[] int[] и т. Д.

Смежные вопросы

2 голосов
/ 22 мая 2010

Основным отличием является то, что в первом случае вы можете вызвать printMax с несколькими аргументами:

printMax(3.0, 4.0, 5.0)

, тогда как во втором случае он будет принимать только один аргумент(массив double).

Внутри тела метода числа будут доступны как массив в обоих случаях.

Следует иметь в виду, что в первом случаевы все равно можете передать один массив double, даже если используется нотация varargs.

1 голос
/ 22 мая 2010

Не совсем - double ... означает список переменных аргументов - все аргументы, переданные в этот момент, будут упакованы в один массив.

В методе может быть только один параметр vararg, и он должен быть последним в своем прототипе по очевидным причинам. Однако он будет доступен в методе в виде массива, поэтому в данном конкретном случае нет большой разницы.

...