
Koray Tugay
das ist von HeadFirst-Java: ( Seite 575 )
Dies:
public <T extends Animal> void takeThing(ArrayList<T> list)
Macht das gleiche:
public void takeThing(ArrayList<? extends Animal> list)
Hier ist also meine Frage: Wenn sie genau gleich sind, warum schreiben wir nicht
public <? extends Animal> void takeThing(ArrayList<?> list)
oder
public void takeThing(ArrayList<T extends Animal> list)
Wann wäre es außerdem sinnvoll, ein ? anstelle eines T in einer Methodendeklaration (wie oben) mit Generics oder für eine Klassendeklaration? Was sind die Vorteile?

Werzi2001
Der große Unterschied zw
public <T extends Animal> void takeThing(ArrayList<T> list)
und
public void takeThing(ArrayList<? extends Animal> list)
ist, dass Sie in der früheren Methode auf “T” innerhalb der Methode als die konkrete Klasse verweisen können, die angegeben wurde. Bei der zweiten Methode ist dies nicht möglich.
Hier ein komplexeres Beispiel zur Veranschaulichung:
// here i can return the concrete type that was passed in
public <T extends Animal> Map<T, String> getNamesMap(ArrayList<T> list) {
Map<T, String> names = new HashMap<T, String>();
for (T animal : list) {
names.put(animal, animal.getName()); // I assume there is a getName() method
}
return names;
}
// here i have to use general Animal
public Map<Animal, String> getNamesMap(ArrayList<? extends Animal> list) {
Map<Animal, String> names = new HashMap<Animal, String>();
for (Animal animal : list) {
names.put(animal, animal.getName()); // I assume there is a getName() method
}
return names;
}
Bei der ersten Methode erhalten Sie, wenn Sie eine Katzenliste übergeben, eine Karte mit der Katze als Schlüssel. Die zweite Methode würde immer eine Map mit allgemeinem Animal-Schlüssel zurückgeben.
Übrigens ist dies keine gültige Java-Syntax:
public <? extends Animal> void takeThing(ArrayList<?> list)
Bei dieser Form der generischen Methodendeklaration müssen Sie einen gültigen Java-Bezeichner verwenden und nicht “?”.
Bearbeiten:
Die Form „? erweitert den Typ“ gilt nur für Variablen- oder Parametertypdeklarationen. Innerhalb einer generischen Methodendeklaration muss es „Identifier extended Type“ sein, da Sie in Ihrer Methode auf den „Identifier“ verweisen können.

bennidi
Bei Wildcards geht es um Co/Contra-Varianz von Generika. Ich werde versuchen, an einigen Beispielen zu verdeutlichen, was das bedeutet.
Grundsätzlich hängt es damit zusammen, dass es sich bei den Typen S und T, wobei S ein Untertyp von T ist, um einen generischen Typ handelt G<S>
ist kein gültiger Untertyp von G<T>
List<Number> someNumbers = new ArrayList<Long>(); // compile error
Abhilfe schaffen Sie mit Wildcards
List<? extends Number> someNumbers = new ArrayList<Long>(); // this works
Bitte beachten Sie, dass Sie nichts in eine solche Liste aufnehmen können
someNumbers.add(2L); //compile error
sogar (und für viele Entwickler überraschender):
List<? extends Long> someLongs = new ArrayList<Long>();
someLongs.add(2L); // compile error !!!
Ich denke, SO ist nicht der richtige Ort, um das im Detail zu diskutieren. Ich werde versuchen, einige der Artikel und Papiere zu finden, die dies ausführlicher erklären.

Markus Peters
Das Binden des Typs an einen Typparameter kann leistungsfähiger sein, je nachdem, was die Methode tun soll. Ich bin mir nicht sicher, was takeThing
tun soll, aber stellen Sie sich im Allgemeinen vor, wir hätten eine Methode mit einer dieser Typsignaturen:
public <T extends Animal> void foo(ArrayList<T> list);
//or
public void foo(ArrayList<? extends Animal> list);
Hier ist ein konkretes Beispiel für etwas, das Sie nur mit dem tun können Erste Typ Unterschrift:
public <T extends Animal> void foo(ArrayList<T> list) {
list.add(list.remove(0)); // (cycle front element to the back)
}
In diesem Fall T
ist erforderlich, um den Typprüfer darüber zu informieren, dass das Element ist ENTFERNT aus der Liste ist ein OK-Element an addieren zur Liste.
Sie könnten dies nicht mit einem Platzhalter tun, da der Platzhalter, da er nicht an einen Typparameter gebunden ist, nicht nachverfolgt wird (naja, er wird durch “Captures” nachverfolgt, aber er kann nicht genutzt werden). Weitere Informationen dazu finden Sie in einer anderen Antwort, die ich gegeben habe: Wie funktionieren Generika von Generika?
Wenn du schreibst ? extends T
Sie sagen “alles, was ein T oder genauer ist”. Zum Beispiel: a List<Shape>
kann nur haben Shape
s darin, während a List<? extends Shape>
haben kann Shape
S, Circle
S, Rectangle
s usw.
Wenn du schreibst ? super T
Sie sagen “alles, was ein T oder allgemeiner ist”. Dies wird seltener verwendet, hat aber seine Anwendungsfälle. Ein typisches Beispiel wäre ein Rückruf: Wenn Sie eine übergeben möchten Rectangle
zurück zu einem Rückruf, den Sie verwenden können Callback<? super Rectangle>
seit einem Callback<Shape>
wird umgehen können Rectangle
s auch.
Hier ist den entsprechenden Wikipedia-Artikel.

dcernahoschi
Wenn dein takeThing
-Methode muss Elemente zu hinzufügen list
-Parameter wird die Wildcard-Version nicht kompiliert.
Der interessante Fall ist, wenn Sie nichts zur Liste hinzufügen und beide Versionen zu kompilieren und zu funktionieren scheinen.
In diesem Fall würden Sie die Wildcard-Version schreiben, wenn Sie verschiedene Tierarten in der Liste zulassen möchten (mehr Flexibilität), und die Parameterversion, wenn Sie eine feste Tierart in der Liste benötigen: den T-Typ.
Zum Beispiel die java.util.Collection
erklärt:
interface Collection<E> {
...
public boolean containsAll(Collection<?> c);
...
}
Und angenommen, Sie haben den folgenden Code:
Collection<Object> c = Arrays.<Object>asList(1, 2);
Collection<Integer> i = Arrays.<Integer>asList(1, 2, 3);
i.containsAll(c); //compiles and return true as expected
Wenn die java.util.Collection
wäre:
interface Collection<E> {
...
public boolean containsAll(Collection<E> c);
...
}
Der obige Testcode würde nicht kompilieren und die Flexibilität des Collection
API würde reduziert werden.
Es ist erwähnenswert, dass die letztere Definition von containsAll
hat den Vorteil, dass zur Kompilierzeit mehr Fehler abgefangen werden, zum Beispiel:
Collection<String> c = Arrays.asList("1", "2");
Collection<Integer> i = Arrays.asList(1, 2, 3);
i.containsAll(c); //does not compile, the integer collection can't contain strings
Verfehlt aber den gültigen Test mit a Collection<Object> c = Arrays.<Object>asList(1, 2);

Rahul Saini
Die Verwendung von Java Generics Wildcards unterliegt dem GET-PUT-Prinzip (das auch als IN-OUT-Prinzip bekannt ist). Darin heißt es:
Verwenden Sie einen “erweiterten” Platzhalter, wenn Sie nur Werte aus einer Struktur erhalten, verwenden Sie einen “Super”-Platzhalter, wenn Sie nur Werte in eine Struktur einfügen, und verwenden Sie keine Platzhalter, wenn Sie beides tun. Dies gilt nicht für den Rückgabetyp einer Methode. Verwenden Sie keinen Platzhalter als Rückgabetyp. Siehe Beispiel unten:
public static<T> void copyContainerDataValues(Container<? extends T> source, Container<? super T> destinationtion){
destination.put(source.get());
}
9939000cookie-checkWann sollten Wildcards in Java Generics verwendet werden?yes
Wie sagt man
public <? extends Animal> void takeThing(ArrayList<?> list)
? Wenn Sie void sagen, gibt es keinen Rückgabetyp. Wenn Sie angeben, gibt es einen Rückgabetyp. Ich wusste nicht, dass Sie angeben können, ob Sie einen Rückgabetyp oder keinen Rückgabetyp haben möchten.– DevZer0
23. Mai 2013 um 7:23 Uhr
stackoverflow.com/questions/13474791/… Dies dient als zukünftige Referenz für alle, die diese Frage sehen!
– Koray Tugay
23. Mai 2013 um 7:46 Uhr