Эквивалентная перегрузка метода зачем нужна?

Я просмотрел некоторый код JAVA, созданный Google, и нашел ImmutableSet: http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/ImmutableSet.html

Они реализовали метод of() несколькими другими способами:

public static <E> ImmutableSet<E> of(E e1, E e2);
public static <E> ImmutableSet<E> of(E e1, E e2, E e3);
public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4);
public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5);
public static <E> ImmutableSet<E> of(E... elements);

Я проверил реализацию, которая находится здесь: https://code.google.com/p/google-collections/source/browse/trunk/src/com/google/common/collect/ImmutableSet.java

Есть метод create со следующей сигнатурой:

private static <E> ImmutableSet<E> create(E... elements)

который обертывает

private static <E> ImmutableSet<E> create(Iterable<? extends E> iterable, int count);

метод. Публичные методы просто передают параметры подписанному методу create(E... elements), который, наконец, вызывает другой метод создания.

Я предполагаю, что общедоступность методов с фиксированным количеством параметров не нужна, поскольку у нас есть метод of(E... elements).

Мой вопрос в том, почему они так поступили? Представление? Или это узор?

Спасибо.


person maestro    schedule 04.02.2014    source источник
comment
Примечание: если вы используете старую библиотеку Google Collections, не делайте этого, она больше не поддерживается. Используйте новый и блестящий Google Guava, который заменяет Коллекции Google (и активно развивается ).   -  person Petr Janeček    schedule 04.02.2014


Ответы (3)


На самом деле это не может быть связано с производительностью: все методы делегируют одному и тому же методу создания, который так или иначе ожидает массив.

Я предполагаю, что это связано с предупреждениями. Рассмотрим следующий минимальный фрагмент:

import java.util.List;

class ImmutableSet<T>
{
}
public class ParametersTest
{
    public static void main(String[] args)
    {
        List<String> list0 = null;
        List<String> list1 = null;
        of(list0, list1);
    }

    @SuppressWarnings("unchecked")
    public static <E> ImmutableSet<E> of(E e1, E e2) {
        return create(e1, e2);
    }

    public static <E> ImmutableSet<E> of(E... elements) {
        return create(elements);
    }

    private static <E> ImmutableSet<E> create(E... elements) 
    {
        return null;
    }

}

Вызов of в основном методе в порядке: он соответствует 2-args-версии метода of. Теперь закомментируйте 2-args-версию of-метода. Тогда вызов все еще в порядке, но будет напрямую вызывать версию varags. Это приведет к созданию универсального массива и вызовет предупреждение. (Очевидно, что это предупреждение скрыто в версии с 2 аргументами).

Подводя итог, я предполагаю, что это сделано для того, чтобы избежать предупреждений для клиентов библиотеки, которые хотят вызвать метод of с несколькими объектами универсального типа.

К счастью, в будущем такие вещи больше не понадобятся благодаря http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html

person Marco13    schedule 04.02.2014
comment
Ты прав. Я нашел это около минуты назад: -that-ta?rq=1" title="почему классы гуавы предоставляют так много фабричных методов, а не только один, который ta">stackoverflow.com/questions/4314883/ Итак, мой вопрос на самом деле дублируется, извините за это, но этот ответ показывает, что этот путь перенаправляется из-за предупреждений. - person maestro; 04.02.2014

Представление. Чтобы вызвать версию метода E..., вызывающая сторона должна выделить новый массив. Вызывающий должен только поместить аргументы в стек, чтобы вызвать другие методы.

person Solomon Slow    schedule 04.02.2014
comment
Но они по-прежнему вызывают вариативную версию create, поэтому массив будет создан в любом случае, не так ли? - person sepp2k; 04.02.2014
comment
Если код скомпилирован JIT и компилятор хорош, он, скорее всего, передаст некоторые или все аргументы в регистры, если метод не является рекурсивным. - person Alex D; 04.02.2014
comment
@AlexD Я почти уверен, что JIT-компилятор не может сделать это с помощью вариативного метода. - person sepp2k; 04.02.2014
comment
@sepp2k sepp2k, если компилятор хорош, почему бы и нет. На любом заданном сайте вызова количество переданных аргументов является известной константой. Специализация по сайту вызова -- очень мощная оптимизация, которая может значительно ускорить работу многих программ. Действительно ли данная JVM выполняет такую ​​оптимизацию или нет, это другой вопрос, и я не знаю ответа. - person Alex D; 05.02.2014

Они делают это для более эффективного управления памятью. Если у вас есть неизменяемая коллекция с небольшим набором элементов, лучше явно зафиксировать размер коллекции. В противном случае Java создаст коллекцию большего размера. Например: HashSet, если не указано иное, будет иметь начальный размер 12 записей.

person gizmo    schedule 04.02.2014
comment
Насколько мне известно, размер неизменяемой коллекции всегда будет соответствовать количеству вставленных элементов, независимо от того, какой метод вы используете для ее создания. И HashSet по умолчанию будет иметь размер 16 (чтобы можно было использовать двоичную операцию AND вместо операции mod при вычислении правильного сегмента из hashCode). Или что-то изменилось в последнее время? - person Petr Janeček; 04.02.2014
comment
Поскольку все упомянутые перегрузки of вызывают один и тот же метод create, я не понимаю, как они могут делать что-то по-другому (например, фиксировать размер). - person sepp2k; 04.02.2014
comment
Ты прав. Я пропустил ту часть, где в конце делегируется уникальный метод. - person gizmo; 04.02.2014