Подтвердить что ты не робот

Почему у EnumSet много перегруженных "из" методов?

Просматривая метод EnumSet<E> of, я видел несколько перегруженных реализаций метода of:

public static <E extends Enum<E>> EnumSet<E> of(E e)

public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2)

.
.

public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4, E e5)

а затем другой перегруженный метод с varargs

public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
    EnumSet<E> result = noneOf(first.getDeclaringClass());
    result.add(first);
    for (E e : rest)
        result.add(e);
    return result;
}

Когда эти varargs могли обрабатывать другие реализации, почему этот метод перегружен таким образом? Есть ли какая-то конкретная причина для этого?

Я прошел через Джавадок того же самого, но я не мог найти убедительного объяснения.

4b9b3361

Ответ 1

Методы Varargs создают массив.

public static void foo(Object... args) {
  System.out.println(args.length);
}

Это работает из-за неявного создания массива. EnumSet - это класс, разработанный очень быстро, поэтому, создав все дополнительные перегрузки, они могут пропустить шаг создания массива в первых нескольких случаях. Это особенно верно, так как во многих случаях Enum не так много элементов, и если они это делают, то EnumSet может не содержать их всех.

Javadoc для EnumSet<E> of(E e1, E e2, E e3, E e4, E e5):

Создает набор перечислений, первоначально содержащий указанные элементы. Перегрузки этого метода существуют для инициализации набора перечислений с одним-пятью элементами. Предоставляется шестую перегрузку, которая использует функцию varargs. Эта перегрузка может быть использована для создания набора перечислений, первоначально содержащего произвольное количество элементов, но, вероятно, будет работать медленнее, чем перегрузки, которые не используют varargs.

Ответ 2

varags создает массив, то есть когда мы вызываем

void x(int...x) {...}
..
x(1);

Компилятор заменяет последнюю строку следующим:

x(new int[] {1});

Это не произойдет, если у нас есть перегруженный метод с 1 arg:

void x(int...x) {...}
void x(int x) {...}

Затем компилятор выберет второй метод.

Ответ 3

Из javadoc:

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

Ответ 4

Потому что этот класс был разработан Джошем Блохом, и этот парень знает, как все работает.:) Помимо создания массива, метод varargs содержит цикл, который больше подходит для JIT для оптимизации кода.

Например, если мы посмотрим на реализацию перегруженной версии с пятью параметрами:

result.add(e1);
result.add(e2);
result.add(e3);
result.add(e4);
result.add(e5);

мы замечаем, что это какой-то уже развернутый цикл, который может выглядеть так:

for (E e : Arrays.asList(e1, e2, e3, e4, e5)) {
   result.add(e);
}

Кроме того, более короткие и более простые методы более склонны быть более строгими, чем более длинные и более сложные.