Die Besetzung ist nicht notwendig.
Die Zuordnungen
ArrayList<?> list = new ArrayList<Integer>();
ArrayList<? extends Number> list2 = new ArrayList<Integer>();
benötigen kein explizites Casting.
Wildcard-Typen sind „allgemeine“/„weniger spezifisch“ Typen als Betontypen und upper bounded wildcard types (wie ? extends Number
) sind spezifischer als unbounded ones (?
).
Weitere Informationen über die Beziehung zwischen Wildcard-Typen finden Sie in der Oracle Tutorial on Wildcards and Subtyping.
Der relevante Teil des JLS Diese Angabe ist 4.10.2. Subtyping among Class and Interface Types
Bei einem gattungsgemäßen Art Erklärung C (n> 0), die direkten geordneten Typen des parametrisierten Typ C, wobei Ti (1 ≤ i ≤ n) ein Typ ist, werden alle der folgenden:
- D, wobei D ein generischer Typ ist, der eine direkte Übertyp der gattungsgemäßen Art C und θ ist, ist die Substitution [F1: = T1, ..., Fn : = Tn].
- C, wobei Si Ti enthält (1 ≤ i ≤ n) (§4.5.1).
[...]
die 4.5.1. Type Arguments of Parameterized Types
Typargument T1 genannten bezieht sich eine andere Art Argument T2 enthalten, geschrieben T2 < = T1, wenn der eingestellte der mit T2 bezeichneten Typen ist nachweisbar eine Teilmenge der mit T1 bezeichneten Arten von Typen unter dem reflexiven und transitiven Schließen der folgenden Regeln (wobei <: Subtyping (§4.10) bedeutet):
[...]
So nach dieser Definition ArrayList<? extends Number>
ist ein übergeordneter Typ von ArrayList<Integer>
und ArrayList<?>
ist ein übergeordneter Typ eines ArrayList<>
mit Ausnahme der rohen Art.
Zuordnung zu einer Variablen eines Typs, der ein Supertype ist, erfordert kein Casting.
Ein Abguss ist notwendig, wenn Sie etwas von einem anderen Typ zuweisen möchten:
Object list = new ArrayList<Integer>();
//...somewhere else - the compiler does not know that list is always an ArrayList, but we tell it that we know what we are doing
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning, but works
Nach dieser Besetzung können Sie zum Beispiel Holen Sie sich Elemente aus der Liste und behandeln Sie sie als Number
s. Die Besetzung wird zur Laufzeit fehlschlagen, wenn Sie etwas anderes zu der list
Referenz zuweisen, das nicht ein Subtyp von List<? extends Number>
Object list = new HashSet<Integer>();
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning
nicht zur Laufzeit werfen
java.lang.ClassCastException: java.util.HashSet cannot be cast to java.util.List
Die Probleme beginnen zu entstehen wenn der generische Typ nicht übereinstimmt:
List<String> stringList = new ArrayList<String>();
stringList.add("hi");
Object list = stringList;
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning, but (sadly) works
Number n = numbers.get(0); //fails: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number
Dies geschieht, weil zur Laufzeit das Löschen der Listentypen übereinstimmt. Siehe auch the tutorial on erasure
Zur Laufzeit gibt es keine Umwandlung, da die generischen Informationen verloren gehen (Typ löschen). Zur Kompilierzeit sagen Sie dem Compiler, dass er 'ArrayList' als 'ArrayList 'und sei still darüber (außer der Warnung, im Grunde ist es das gleiche, als würdest du eine' Number' Variable in 'Integer' umwandeln - du sagst dem Compiler, dass du weißt was du tust). Die Zuweisung zu 'ArrayList >' funktioniert in jedem Fall. –
Thomas
Mit Generics sollte Gießen überhaupt nicht notwendig sein. Wenn Sie einen generischen Typ verwenden möchten, sollten Sie vielleicht prüfen, ob es keine "saubere" Lösung ohne Cast gibt, indem Sie einfach die enorme Flexibilität nutzen, die Generics haben. Ich bin sicher, dass viele Menschen bereit sind zu helfen, wenn Sie ein konkretes Beispiel haben. – martinhh
Ich habe ein konkretes Beispiel. Ich arbeite mit framwork, das erlaubt, JUnit-Test zu kommentieren, um Speicher zu wählen, den ich Resultate an '' ReesmoConfiguration (Speicher = RestApiStorage.class) 'senden möchte und in der abstrakten Oberklasse Speicher fand ich Fabrikmethode ' newInstance (Gegenstandkonfiguration) { Klasse erweitert Speicher> clazz = null; if (Bool.FALSE.equals (Property.ENABLED.get (Konfiguration))) { clazz = DummyStorage.class; } else { clazz = (Klasse Erweitert Speicher>) Property.STORAGE.get (Konfiguration); } if (clazz.isAssignableFrom (DummyStorage.class)) { Rückgabe von neuem DummyStorage(); }} ' –