2009-03-06 4 views

Antwort

16

Es gibt keinen praktischen Unterschied in Bezug darauf, was Sie tun können, wenn Sie einen davon haben, da der type-Parameter nur in einer "output" -Position verwendet wird. Auf der anderen Seite gibt es einen großen Unterschied in Bezug darauf, was Sie als einer von ihnen verwenden können.

Angenommen, Sie hatten eine Enumeration<JarEntry> - Sie konnten dies nicht an eine Methode übergeben, die Enumeration<ZipEntry> als eines ihrer Argumente nahm. Sie könnte übergeben es zu einer Methode unter Enumeration<? extends ZipEntry> obwohl.

Es ist interessanter, wenn Sie einen Typ haben, der den Typ-Parameter sowohl in der Eingabe- als auch in der Ausgabeposition verwendet - List<T> ist das offensichtlichste Beispiel. Hier sind drei Beispiele für Methoden mit Variationen eines Parameters. In jedem Fall versuchen wir, einen Gegenstand aus der Liste zu holen und fügen einen weiteren hinzu.

// Very strict - only a genuine List<T> will do 
public void Foo(List<T> list) 
{ 
    T element = list.get(0); // Valid 
    list.add(element); // Valid 
} 

// Lax in one way: allows any List that's a List of a type 
// derived from T. 
public void Foo(List<? extends T> list) 
{ 
    T element = list.get(0); // Valid 
    // Invalid - this could be a list of a different type. 
    // We don't want to add an Object to a List<String> 
    list.add(element); 
} 

// Lax in the other way: allows any List that's a List of a type 
// upwards in T's inheritance hierarchy 
public void Foo(List<? super T> list) 
{ 
    // Invalid - we could be asking a List<Object> for a String. 
    T element = list.get(0); 
    // Valid (assuming we get the element from somewhere) 
    // the list must accept a new element of type T 
    list.add(element); 
} 

Für weitere Details lesen:

+0

Eine ZipEntrySubclass wie JarEntry (der Grund, warum ZipFile.entries einen Platzhalter verwendet)? –

+0

Danke Tom - werde meine Antwort bearbeiten :) –

4

Ja, gerade aus einem der sun generics tutorials:

Hier Shape ist eine abstrakte Klasse mit drei Unterklassen: Kreis, Rechteck, und Dreieck.

public void draw(List<Shape> shape) { 
    for(Shape s: shape) { 
    s.draw(this); 
    } 
} 

Es ist erwähnenswert, dass die draw() Methode kann nur auf Listen von Form aufgerufen wird und kann nicht auf einer Liste von Kreis, Rechteck und Dreieck für Beispiel genannt werden. Um das Verfahren zu haben akzeptieren jede Art von Form, sollte es wie folgt geschrieben werden:

public void draw(List<? extends Shape> shape) { 
    // rest of the code is the same 
} 
+0

Dies ist das zweite Mal in dieser Woche Jon Skeet hat eine Antwort in direkt vor mir bekommen. Ich schlage vor, wir bezeichnen dies als Skeeting. – GaryF

+0

hört sich gut an. Was wäre die Vergangenheitsform? Sket? "Jon Skeet skizziert mich wieder!" :) – Epaga

+0

http://stackoverflow.com/questions/305223/jon-skeet-facts/317486#317486 –

0

Jetzt hast du einfach weg und erinnerte mich an etwas, was ich wünschte, wir in der C# Welt hatte über .

Anders als die Links zur Verfügung gestellt, es gibt ein paar gute Links zu C# und Java in Bezug auf dieses Thema in den Antworten auf diese Frage: Logic and its application to Collections.Generic and inheritance

Eine Auswahl davon:

Verwandte Themen