Was sind die Unterschiede zwischen List
, List<?>
, List<T>
, List<E>
, und List<Object>
?
1. Liste
List
: ist ein Rohtyp, daher nicht typesafe
. Es wird nur dann ein Laufzeitfehler generiert, wenn das Casting schlecht ist. Wir möchten einen Fehler bei der Kompilierung, wenn die Besetzung schlecht ist. Nicht zu empfehlen.
2. Liste <?>
List<?>
ist eine unbegrenzte Wildcard. Aber ich bin nicht sicher, wofür es ist? Ich kann List<?>
ohne Probleme drucken :
public static void test(List<?> list){
System.out.println(list); // Works
}
Warum kann ich keine Elemente zu einem hinzufügen List<?>
?
public static void test(List<?> list){
list.add(new Long(2)); // Error
list.add("2"); // Error
System.out.println(list);
}
3. Listen Sie <T> auf
public static void test(List<T> list){ // T cannot be resolved
System.out.println(list);
}
Ich verstehe diese Syntax nicht. Ich habe so etwas gesehen und es funktioniert:
public <T> T[] toArray(T[] a){
return a;
}
Manchmal sehe ich <T>
, oder <E>
, oder <U>
, <T,E>
. Sind sie alle gleich oder repräsentieren sie etwas anderes?
4. Listen Sie <Objekt> auf
Dies gibt den Fehler "Die Methode test(List<Object>)
ist für das Argument nicht anwendbar List<String>
":
public static void test(List<Object> list){
System.out.println(list);
}
Wenn ich das versuche, bekomme ich "Kann nicht von List<String>
bis gewirkt werden List<Object>
":
test((List<Object>) names);
Ich bin verwirrt. String
ist eine Unterklasse von Object
, warum ist also keine List<String>
Unterklasse von List<Object>
?
2
. Ich schreibe einige Codes, um dies zu demonstrieren2
. tyvmList<Object>
für verwenden?Für den letzten Teil: Obwohl String eine Teilmenge von Object ist, wird List <String> nicht von List <Object> geerbt.
quelle
List<Object>
für verwenden?Die Notation
List<?>
bedeutet "eine Liste von etwas (aber ich sage nicht was)". Da der Code intest
für jede Art von Objekt in der Liste funktioniert, funktioniert dies als formaler Methodenparameter.Für die Verwendung eines Typparameters (wie in Punkt 3) muss der Typparameter deklariert werden. Die Java-Syntax dafür ist,
<T>
vor die Funktion zu stellen. Dies ist genau analog zum Deklarieren formaler Parameternamen für eine Methode, bevor die Namen im Methodenkörper verwendet werden.Wenn man a
List<Object>
nicht akzeptiertList<String>
, macht das Sinn, weil aString
nicht istObject
; es ist eine Unterklasse vonObject
. Das Update ist zu deklarierenpublic static void test(List<? extends Object> set) ...
. Aber dannextends Object
ist das überflüssig, weil jede Klasse direkt oder indirekt erweitert wirdObject
.quelle
List<Object>
für verwenden?List<?>
da die Liste von einem bestimmten, aber unbekannten Typ ist.List<Object>
wäre wirklich "eine Liste von allem", da es tatsächlich alles enthalten kann.Der Grund, auf den Sie nicht umwandeln können
List<String>
,List<Object>
ist, dass Sie damit die Einschränkungen desList<String>
.Denken Sie an das folgende Szenario: Wenn ich ein habe
List<String>
, soll es nur Objekte vom Typ enthaltenString
. (Die einfinal
Klasse)Wenn ich das in a
List<Object>
umwandeln kann, kann ichObject
diese Liste ergänzen und damit gegen den ursprünglichen Vertrag von verstoßenList<String>
.Wenn also Klasse
C
von Klasse erbtP
, kann man im Allgemeinen nicht sagen, dassGenericType<C>
auch von Klasse erbtGenericType<P>
.NB Ich habe dies bereits in einer früheren Antwort kommentiert, wollte es aber erweitern.
quelle
List<Object>
?List<Object>
da es den Zweck von Generika irgendwie zunichte macht. Es gibt jedoch Fälle, in denen alter Code möglicherweiseList
unterschiedliche Typen akzeptiert. Daher möchten Sie den Code möglicherweise nachrüsten, um die Typparametrisierung zu verwenden, um Compiler-Warnungen für Rohtypen zu vermeiden. (Aber die Funktionalität ist unverändert)Ich würde empfehlen, Java-Puzzler zu lesen. Es erklärt Vererbung, Generika, Abstraktionen und Platzhalter in Deklarationen recht gut. http://www.javapuzzlers.com/
quelle
Lassen Sie uns im Kontext der Java-Geschichte darüber sprechen.
List
::Liste bedeutet, dass es jedes Objekt enthalten kann. Liste war in der Version vor Java 5.0; Java 5.0 führte List aus Gründen der Abwärtskompatibilität ein.
List<?>
::?
bedeutet unbekanntes Objekt, kein Objekt; Die Wildcard-?
Einführung dient zur Lösung des von Generic Type erstellten Problems. siehe Platzhalter ; Dies verursacht aber auch ein anderes Problem:List< T> List< E>
Bedeutet generische Deklaration unter der Voraussetzung, dass in Ihrem Projekt Lib kein T- oder E-Typ vorhanden ist.
List< Object>
bedeutet generische Parametrisierung.quelle
In Ihrem dritten Punkt kann "T" nicht aufgelöst werden, da es nicht deklariert ist. Wenn Sie eine generische Klasse deklarieren, können Sie normalerweise "T" als Namen des gebundenen Typparameters verwenden . Viele Online-Beispiele, einschließlich
der Tutorials von Orakel,verwenden "T" als Name des Typparameters, z. B. deklarieren Sie eine Klasse wie:Sie sagen, dass die
FooHandler's
operateOnFoo
Methode eine Variable vom Typ "T" erwartet, die in der Klassendeklaration selbst deklariert ist. Vor diesem Hintergrund können Sie später eine andere Methode wie hinzufügenIn allen Fällen, in denen entweder T, E oder U alle Bezeichner des Typparameters enthalten, können Sie sogar mehr als einen Typparameter haben, der die Syntax verwendet
In Ihrem vierten Ponint ist Sting zwar effektiv ein Subtyp von Objekt, in generischen Klassen gibt es jedoch keine solche Beziehung, es
List<String>
gibt keinen Subtyp, daList<Object>
es sich aus Compilersicht um zwei verschiedene Typen handelt. Dies wird am besten in diesem Blogeintrag erklärtquelle
Theorie
String[]
kann gegossen werdenObject[]
aber
List<String>
kann nicht gegossen werdenList<Object>
.Trainieren
Bei Listen ist dies subtiler, da beim Kompilieren der Typ eines an eine Methode übergebenen List-Parameters nicht überprüft wird. Die Methodendefinition könnte genauso gut sagen
List<?>
- aus Sicht des Compilers ist sie äquivalent. Aus diesem Grund gibt das Beispiel Nr. 2 des OP Laufzeitfehler und keine Kompilierungsfehler.Wenn Sie einen
List<Object>
an eine Methode übergebenen Parameter sorgfältig behandeln, damit Sie keine Typprüfung für ein Element der Liste erzwingen, können Sie Ihre Methode definieren lassen, indem SieList<Object>
einenList<String>
Parameter aus dem aufrufenden Code akzeptieren .A. Dieser Code gibt also keine Kompilierungs- oder Laufzeitfehler und funktioniert tatsächlich (und vielleicht überraschend?):
B. Dieser Code gibt einen Laufzeitfehler aus:
C. Dieser Code gibt einen Laufzeitfehler aus (
java.lang.ArrayStoreException: java.util.Collections$UnmodifiableRandomAccessList Object[]
):In B ist der Parameter zur Kompilierungszeit
set
nicht typisiertList
: Der Compiler sieht ihn alsList<?>
. Es liegt ein Laufzeitfehler vor, da zur Laufzeitset
das eigentliche Objekt übergeben wird, von dem übergeben wirdmain()
, und das ist aList<String>
. AList<String>
kann nicht besetzt werdenList<Object>
.In C
set
erfordert der Parameter eineObject[]
. Es gibt keinen Kompilierungsfehler und keinen Laufzeitfehler, wenn es mit einemString[]
Objekt als Parameter aufgerufen wird. Das liegt daran, dassString[]
Casts zuObject[]
. Aber das tatsächliche Objekt, das von empfangen wird,test()
bleibt einString[]
, es hat sich nicht geändert. So wird dasparams
Objekt auch zu einemString[]
. Und Element 0 von aString[]
kann nicht a zugewiesen werdenLong
!(Hoffentlich habe ich hier alles richtig gemacht, wenn meine Argumentation falsch ist, werde ich es sicher von der Community erfahren. AKTUALISIERT: Ich habe den Code in Beispiel A so aktualisiert, dass er tatsächlich kompiliert wird, während ich immer noch den gemachten Punkt zeige.)
quelle
List<Object> cannot be applied to List<String>
. Sie können nicht passierenArrayList<String>
ein Verfahren , das erwartetArrayList<Object>
.Problem 2 ist in Ordnung, weil "System.out.println (set);" bedeutet "System.out.println (set.toString ());" set ist eine Instanz von List, daher ruft Complier List.toString () auf.
Problem 3: Diese Symbole sind gleich, aber Sie können ihnen unterschiedliche Spezifikationen geben. Beispielsweise:
Problem 4: Die Sammlung erlaubt keine Typparameter-Kovarianz. Aber Array erlaubt Kovarianz.
quelle
Sie haben Recht: String ist eine Teilmenge von Object. Da String "präziser" als Object ist, sollten Sie ihn umwandeln, um ihn als Argument für System.out.println () zu verwenden.
quelle