2015-04-08 14 views
5

Kiedy kopie w źródło zbioru gs dla ImmutableList, nie rozszerza java.util.List. Jednak klasa javadoc wspomniała, że ​​wszystkie implementacje ImmutableList muszą implementować java.util.List.ImmutableList nie rozszerza listy?

Dlaczego trzeba poprosić o wdrożenie, aby wdrożyć java.util.List, a nie sam ImmutableList, aby przedłużyć java.util.List?

+2

Co * nie * rozszerza? –

+1

W katalogu głównym rozszerza 'java.lang.Iterable' – Wins

+0

Dziwny wzór. Zamiast umieszczać niewykonalne wymagania w Javadoc, mogli napisać: 'extends java.util.Lista' i wymuszenie go automatycznie. – EJP

Odpowiedz

11

Dlaczego ImmutableList przedłużyć List?

ImmutableCollection nie rozciąga java.util.Collection (i ImmutableList nie rozciąga java.util.List), ponieważ Collection ma mutację metod, takich jak add() i remove(). Gdyby niezmienne zbiory miały te metody, zawsze musiałyby rzucać UnsupportedOperationException. Dla użytkowników niezmiennych kolekcji, byłoby dziwne, gdyby opcje autouzupełniania były dostępne jako metody wywoływalne.

Dlaczego Javadoc narzuca umowę, że wszystkie implementacje ImmutableList implementują również List?

Sprowadza się do równości. Numer ImmutableList powinien być równy List, zakładając, że obie listy mają tę samą zawartość w tej samej kolejności. List.equals() imposes a Javadoc contract który stanowi:

Zwraca true wtedy i tylko wtedy, gdy określony obiekt jest także lista obie wykazy mają tę samą wielkość, a wszystkie odpowiadające im pary elementów dwie listy są równe.

Co to znaczy, że "określony obiekt to także lista?" Możemy zobaczyć w AbstractList.equals(), że oznacza to instanceof List.

public boolean equals(Object o) { 
    if (o == this) 
     return true; 
    if (!(o instanceof List)) 
     return false; 
    ... 
} 

Więc wszystkie ImmutableList implementacje muszą też wdrożyć List dla equals() pracować w sposób symetryczny. Niezmienne fabryki kolekcji już ukrywają szczegóły implementacji, takie jak fakt, że niezmienna lista z pojedynczym elementem jest zaimplementowana przez ImmutableSingletonList. Zapełnia się również ukrywanie interfejsu List.

ImmutableList class diagram

Interop

Zaletą tego rozwiązania jest to, że ImmutableList można odlewać do List co jest ważne dla współdziałanie z istniejącymi API.

// Library method - cannot refactor the parameter type 
public void printAll(List<?> list) 
{ 
    for (Object each : list) 
    { 
     System.out.println(each); 
    } 
} 

ImmutableList<Integer> immutableList = Lists.immutable.with(1, 2, 3); 
List<Integer> castList = immutableList.castToList(); 
printAll(castList); 
// also works 
printAll((List<?>) immutableList); 

// throws UnsupportedOperationException 
castList.add(4); 

Uwaga: Jestem deweloperem na GS Collections.

+2

Dzięki za długa odpowiedź, ma to sens, ale domyślam się, że to jeden z aspektów projektowania . Osobiście wolałbym dodać() i remove(), aby rzucić UnsupportedOperationException zamiast wywoływać castToList(). Programista powinien wiedzieć, że jeśli kod używa ImmutableList, dodawanie i usuwanie nie będzie działało i to jest problem programisty, a nie kwestia projektu. Przypuszczam, że to tylko osobista opinia. Jeszcze raz dziękuję za odpowiedź: – Wins

+2

Myślę, że możesz być zainteresowany UnmodifiableMutableList i jego fabryczną metodą MutableList.asUnmodifiable(). Pozostawiłem tę odpowiedź ograniczoną do ImmutableList, ale nie wahaj się zadać nowego pytania na temat różnic, a ja wrócę i napiszę więcej. –

+2

Rozumiem UnmodifiableMutableList (nazwa jest bardzo jawna), ale pytam: dlaczego nie uczynić ImmutableList, aby rozszerzyć listę, rzucić UnsupportedOperationException na dodawanie i usuwanie, ale zachować niezmienność listy i obiektów, które zawiera. – Wins

Powiązane problemy