Претоварване на еквивалентен метод защо е необходимо?

Прегледах някакъв 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

Има метод за създаване със следния подпис:

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 Колекции, недейте, тя вече не се поддържа. Използвайте новата и лъскава 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-args-очевидно).

И така, за да обобщя, предполагам, че това е, за да се избегнат предупреждения за клиенти на библиотеката, които искат да извикат метода of с няколко обекта от общ тип.

За щастие неща като това вече няма да са необходими в бъдеще, благодарение на http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html

person Marco13    schedule 04.02.2014
comment
Прав си. Намерих това преди около една минута: 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, ако компилаторът е добър, няма причина да не е така. Във всеки даден сайт за повикване броят на предадените аргументи е известна константа. Специализация на сайта за обаждания -- много мощна оптимизация, която може да направи много програми много по-бързи. Дали дадена JVM наистина прави такъв вид оптимизация или не е друг въпрос и аз не знам отговора. - person Alex D; 05.02.2014

Те го правят, за да управляват паметта по по-ефективен начин. Ако имате неизменна колекция с малък набор от елементи, по-добре е изрично да фиксирате размера на колекцията. В противен случай Java ще създаде колекция с по-голям размер. Например: HashSet, освен ако не е указано друго, ще има първоначален размер от 12 записа.

person gizmo    schedule 04.02.2014
comment
AFAIK, една неизменна колекция винаги ще бъде оразмерена по подходящ начин спрямо броя на вмъкнатите елементи, без значение какъв метод използвате, за да я създадете. И 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