2013-05-07 17 views
7

Zgodnie literaturze czytałem, mamy soczyste owoce implementign następujący interfejs:ograniczony sposób ogólny z „super” typu

public interface Juicy<T> { 
    Juice<T> squeeze(); 
} 

Korzystanie ograniczone zmienne typu, następujące metody byłoby taks kiść owoców i ścisnąć je wszystkich:

<T extends Juicy<T>> List<Juice<T>> squeeze(List<T> fruits); 

teraz musimy niższe rodzeństwo jak poniżej pracować zbyt:

class Orange extends Fruit implements Juicy<Orange>; 
class RedOrange extends Orange; 

Więc spodziewałbym metoda wyglądać następująco:

<T extends Juicy<T>> List<Juice<? super T>> squeeze(List<? extends T> fruits); 

Zamiast znajdę podpis metoda być jak poniżej:

<**T extends Juicy<? super T>>** List<Juice<? super T>> squeezeSuperExtends(List<? extends T> fruits); 

Co tłumaczy tę różnicę?

+0

że nie powinno być 'public interface Juicy >'? (aby zapobiec "klasy Orange rozszerza Owoce implementuje Juicy ') – SLaks

+0

@SLaks: To nie jest wielki zysk, jak gdyby 'Apple' wdrożony' Juicy 'wtedy wspomniany przypadek nie zostanie powstrzymany. –

+0

@MarkPeters: Masz rację; nie ma sposobu, aby temu zapobiec. Zapobiegnie to jednak "rozwojowi klasy Orange w owocach Juicy " – SLaks

Odpowiedz

3

Numer <? super T> w obrębie <T extends Juicy<? super T>> jest dostępny pod numerem RedOrange, który jest podklasą .

Wyobraź bez <? super T> pierwszy:

public <T extends Juicy<T>> List<Juice<T>> squeeze(List<T> fruits) {... 

Teraz T musi być Juicy<T>. Klasa Orange jest Juicy<T>, jest to Juicy<Orange>. Ale klasa RedOrange nie jest Juicy<T>. To nie jest Juicy<RedOrange>; to jest Juicy<Orange>. Kiedy więc próbować wywołać squeeze:

List<RedOrange> redOranges = new ArrayList<RedOrange>(); 
List<Juice<RedOrange>> juices = squeeze(redOranges); 

otrzymujemy następujący błąd kompilatora:

Inferred type 'RedOrange' for type parameter 'T' is not within its bound; should implement 'Juicy<RedOrange>'. 

Jeśli umieszczamy <? super T>, który umożliwia parametr typu dla Juicy być nadklasą T. Pozwala to na użycie RedOrange, ponieważ jest to Juicy<Orange>, a Orange jest nadklasą dla RedOrange.

public <T extends Juicy<? super T>> List<Juice<T>> squeeze(List<T> fruits) {... 

Teraz połączenie powyżej squeeze kompiluje.

EDIT

Ale co, jeśli chcemy squeezeList<Juice<Orange>> z List<RedOrange>? Zrobiło się trochę skomplikowane, ale znalazłem rozwiązanie:

potrzebujemy drugi parametr typu dopasować Orange w metodzie squeeze:

public <S extends Juicy<S>, T extends Juicy<S>> List<Juice<S>> squeeze(List<T> fruits) 

Tutaj S reprezentuje Orange, tak, że możemy wrócić List<Juice<Orange>>.Teraz możemy powiedzieć

List<RedOrange> redOranges = new ArrayList<RedOrange>(); 
List<Juice<Orange>> juices = squeeze(redOranges); 
+0

Podoba mi się ta odpowiedź, ale pomóżcie mi przemyśleć, dlaczego powinniście * otrzymać * listę "List > od wyciskania" Listy ". 'RedOrange' produkuje' Juice ', a nie' Juice ', więc czy metoda' squeeze' nie byłaby niesprawna (tj. Niemożliwe do bezpiecznego/poprawnego wdrożenia)? –

+1

@MarkPeters - Interesujące. Dodałem sposób, aby uzyskać "List >". – rgettman

+0

Chodzi mi o to, że jeśli * możesz * mieć deklarację 'List > juices = squeeze (redOranges)', to coś jest zdecydowanie nie tak, ponieważ 'RedOrange' nie wytwarza' Juice '. Spróbuj bezpiecznie wdrożyć wyciskanie. Podejrzewam, że nie możesz. –

3

Wydaje mi najprostszy sposób myślenia o to, aby na krótko ignorować zależność pomiędzy rodzajem owoców i rodzaju soków owocowych produkuje. Związek ten został ustalony w deklaracji klasowej; nie potrzebujemy tego, aby wycisnąć kilka Juicy s.

Innymi słowy, tylko parametryzacji od rodzaju Juice że Juicy s będzie produkować:

<T> List<Juice<T>> squeeze(List<? extends Juicy<? extends T>> fruits); 

Tutaj produkujemy listę soków opartą na wspólnej Super rodzaju produkowanego Juice (czyli parametr Juicy), nie jest to typowy super owoc.

Następnie otrzymujemy następujące:

//works 
List<Juice<Orange>> b = squeeze(Arrays.asList(new Orange(), new RedOrange())); 

//fails as it should 
List<Juice<RedOrange>> d = squeeze(Arrays.asList(new RedOrange())); 
+0

+1, Masz prostsze rozwiązanie do generowania 'List >' niż ja. – rgettman

+0

+1 za niesamowitą prostotę – IUnknown

Powiązane problemy