2013-05-07 15 views
7

Laut einer Literatur, die wir lesen, haben wir saftige Früchte implementign die folgende Schnittstelle:begrenzt generische Methode mit ‚Super‘ Typ

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

beschränkten Typen Variablen verwenden, die Methode folgende würde ein Bündel von Früchten taks und quetscht sie alle:

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

Jetzt brauchen wir niedrigere Geschwister, wie unten zu arbeiten:

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

Also ich würde das Verfahren erwarten, wie folgt aussehen:

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

Stattdessen finde ich die Methodensignatur, wie unten zu sein:

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

Was dieser Unterschied erklärt?

+0

Sollte das nicht 'sein öffentliche Schnittstelle Juicy >'? (um zu verhindern, dass die Klasse Orange sich ausdehnt Obst verwendet Juicy ') – SLaks

+0

@SLaks: Es ist kein großer Gewinn, als wenn' Apple' 'Juicy ' implementiert hätte, dann würde der Fall, den Sie erwähnen, nicht verhindert werden. –

+0

@MarkPeters: Du hast recht; Es gibt keine Möglichkeit, das zu verhindern. Es würde jedoch verhindern, "Klasse Orange erstreckt sich Obst Geräte Juicy " – SLaks

Antwort

3

Die <? super T> innerhalb <T extends Juicy<? super T>> ist da, so dass RedOrange, die eine Unterklasse von Juicy<Orange> ist, innerhalb ihrer Grenzen sein kann.

Stellen Sie sich vor, ohne die <? super T> zuerst:

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

Jetzt T muss ein Juicy<T> sein. Die Klasse Orange ist eine Juicy<T>, es ist eine Juicy<Orange>. Aber die Klasse RedOrange ist keine Juicy<T>. Es ist kein Juicy<RedOrange>; es ist ein Juicy<Orange>. Also, wenn wir versuchen, squeeze zu nennen:

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

wir den folgenden Compiler-Fehler:

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

Wenn wir die <? super T> platzieren, das erlaubt den Typ Parameter für Juicy eine Oberklasse von T zu sein. Dies erlaubt RedOrange verwendet werden, weil es eine Juicy<Orange> ist, und Orange ist eine Superklasse zu RedOrange.

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

nun der Aufruf an squeeze kompiliert oben.

EDIT

Aber was, wenn wir zu squeeze wollen ein List<Juice<Orange>> von einem List<RedOrange>? Es hat ein wenig schwierig, aber ich fand eine Lösung:

Wir brauchen einen zweiten Typ Parameter Orange im squeeze Methode zum Spiel:

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

Hier S stellt Orange, so dass wir List<Juice<Orange>> zurückkehren können.Jetzt können wir sagen,

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

Ich mag diese Antwort, aber helfen Sie mir, darüber nachzudenken, warum Sie * in der Lage sein sollten, eine 'Liste >' aus einer 'Liste ' zu entsorgen. Ein 'RedOrange' produziert' Juice ', nicht' Juice 'also wäre die' squeeze' Methode nicht unerfüllbar (d. H. Unmöglich sicher/korrekt zu implementieren)? –

+1

@MarkPeters - Interessant. Ich habe einen Weg hinzugefügt, um eine 'Liste >' zu bekommen. – rgettman

+0

Mein Punkt ist mehr, dass wenn Sie eine Deklaration 'Liste > Säfte = Squeeze (redOranges) haben können, dann ist etwas definitiv falsch, weil ein' RedOrange' nicht 'Juice ' produziert. Versuchen Sie, Squeeze sicher anzuwenden. Ich vermute, du kannst nicht. –

3

Es scheint mir der einfachste Weg, darüber nachzudenken, das ist zu kurz, die die Beziehung zwischen der Art der Frucht zu ignorieren und die Art der Fruchtsaft sie produziert. Diese Verbindung ist in der Klassendeklaration festgelegt; wir brauchen es nicht, um einen Haufen von Juicy s auszuquetschen.

Mit anderen Worten, parametrieren nur von der Art der Juice, dass die Juicy s produzieren:

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

Hier stellen wir eine Liste von Säften auf der Grundlage der gemeinsamen Supertyp erzeugt Juice (dh der Parameter Juicy), nicht die gemeinsame super Art von Obst.

Dann erhalten wir folgendes:

//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, Sie haben eine einfachere Lösung zum Generieren einer 'List >' als ich. – rgettman

+0

+1 für die erstaunliche Einfachheit – IUnknown

Verwandte Themen