Unterschied zwischen Liste, Liste , Liste , Liste und Liste

Was sind die Unterschiede zwischen List , List , List , List und List ?

Jetzt stelle ich diese Frage nicht blind, also bitte diesen Thread nicht schließen. Lassen Sie mich zuerst den Basiscode vorstellen:

 private static List names = new ArrayList(); static { names.add("Tom"); names.add("Peter"); names.add("Michael"); names.add("Johnson"); names.add("Vlissides"); } public static void test(List set){ System.out.println(set); } public static void main(String args[]){ test(names); } 

Ich verstehe das:

1. List : ist ein typesafe , daher nicht typesafe . Es wird nur einen Laufzeiterrors erzeugen, wenn das Casting schlecht ist. Wir wollen einen Kompilierzeiterrors, wenn die Besetzung schlecht ist. Nicht empfohlen zu verwenden.

2. List : Ist ein unbeschränkter Platzhalter. Aber nicht sicher, wofür das ist? Also wenn ich die test auf ändern

 public static void test(List set){ System.out.println(set); } 

es funktioniert immer noch gut. Wenn Sie die Verwendung von diesem erklären können, würde ich es sehr schätzen.

EDIT : Wenn ich das mache:

 public static void test(List set){ set.add(new Long(2)); //--> Error set.add("2"); //--> Error System.out.println(set); } 

aber wenn ich den test zu diesem ändern:

 public static void test(List set){ set.add(new Long(2)); //--> Error set.add("2"); //--> Work System.out.println(set); } 

3. List :

 public static void test(List set){ //T cannot be resolved System.out.println(set); } 

Ich denke, ich verstehe diese Syntax nicht. Ich habe so etwas gesehen und es funktioniert:

 public  T[] toArray(T[] a){ return a; } 

Bitte erläutern Sie das bitte für mich? Manchmal sehe ich oder oder , . Sind sie alle gleich oder repräsentieren sie etwas anderes?

4. List

 public static void test(List set){ System.out.println(set); } 

Dann habe ich den Fehler The method test(List) is not application for the argument List für den folgenden Code. Ich bin verwirrt. Ich dachte String eine Teilmenge von Object ?

 public static void main(String args[]){ test(names); } 

EDIT: Wenn ich das versuche

 test((List)names); 

dann habe ich Cannot cast from List to List

1) Korrekt

2) Sie können sich diese als “Nur-Lesen” -Liste vorstellen, in der Sie sich nicht um den Typ der Elemente kümmern. Sie könnte zB von einer Methode verwendet werden, die die Länge der Liste zurückgibt.

3) T, E und U sind gleich, aber Leute neigen dazu, zB T für Typ, E für Element, V für Wert und K für Schlüssel zu verwenden. Die Methode, die kompiliert, besagt, dass ein Array eines bestimmten Typs benötigt wurde, und gibt ein Array desselben Typs zurück.

4) Sie können Orangen und Äpfel nicht mischen. Sie könnten Ihrer String-Liste ein Objekt hinzufügen, wenn Sie eine String-Liste an eine Methode übergeben könnten, die Objektlisten erwartet. (Und nicht alle Objekte sind Strings)

Für den letzten Teil: Obwohl String eine Teilmenge von Object ist, wird List nicht von List geerbt.

Die Notation List< ?> Bedeutet “eine Liste von etwas (aber ich sage nicht was”). Da der Code im test für jedes Objekt in der Liste funktioniert, funktioniert dies als ein formaler Methodenparameter.

Bei Verwendung eines Typparameters (wie in Punkt 3) muss der Typparameter deklariert werden. Die Java-Syntax dafür ist vor die function zu stellen. Dies ist genau so zu sehen, als würden vor der Verwendung der Namen im Methodenkörper formale Parameternamen einer Methode deklariert werden.

Wenn List eine List List nicht akzeptiert, ist das sinnvoll, weil eine String nicht Object ; Es ist eine Unterklasse von Object . Das Problem besteht darin, den public static void test(List< ? extends Object> set) ... zu deklarieren public static void test(List< ? extends Object> set) ... Aber dann ist das extends Object überflüssig, weil jede class direkt oder indirekt das Object .

Der Grund, warum Sie List in List besteht darin, dass Sie die Einschränkungen der List verletzen könnten.

Denken Sie über folgendes Szenario nach: Wenn ich eine List , soll sie nur Objekte vom Typ String . (Was ist eine final class)

Wenn ich das in ein List kann, erlaubt es mir, Object zu dieser Liste hinzuzufügen, wodurch der ursprüngliche Vertrag von List verletzt wird.

Wenn also die class C von der class P erbt, kann man nicht sagen, dass GenericType auch von GenericType

erbt.

NB Ich habe das bereits in einer früheren Antwort kommentiert, wollte es aber weiter ausbauen.

Ich würde empfehlen Java Puzzler zu lesen. Es erklärt inheritance, Generics, Abstraktionen und Platzhalter in Deklarationen ziemlich gut. http://www.javapuzzlers.com/

In Ihrem dritten Punkt kann “T” nicht aufgetriggers werden, weil es nicht deklariert wird. Wenn Sie eine generische class deklarieren, können Sie “T” als Name des gebundenen Typparameters verwenden . Viele Online-Beispiele einschließlich Oracle-Tutorials verwenden “T” als Name des Typparameters, sagen Sie zum Beispiel, eine class wie:

 public class FooHandler { public void operateOnFoo(T foo) { /*some foo handling code here*/} } 

Sie sagen, dass die FooHandler's Methode von FooHandler's eine Variable vom Typ “T” erwartet, die in der classndeklaration selbst deklariert ist. In diesem Sinne können Sie später eine andere Methode hinzufügen

 public void operateOnFoos(List foos) 

in allen Fällen entweder T, E oder U dort alle Bezeichner des Typparameters, können Sie sogar mehr als einen Typparameter haben, der die Syntax verwendet

 public class MyClass {} 

in Ihrem vierten Fall ist zwar effektvoll Sting ein Untertyp von Objekt, in Generika-classn gibt es keine solche Beziehung, List ist kein Untertyp von List sie sind zwei verschiedene Typen aus der Sicht des Compilers, dies Dies wird am besten in diesem Blogeintrag erklärt

Problem 2 ist OK, weil “System.out.println (set);” bedeutet “System.out.println (set.toString ());” set ist eine Instanz von List, also ruft compiler List.toString () auf;

 public static void test(List< ?> set){ set.add(new Long(2)); //--> Error set.add("2"); //--> Error System.out.println(set); } Element ? will not promise Long and String, so complier will not accept Long and String Object public static void test(List set){ set.add(new Long(2)); //--> Error set.add("2"); //--> Work System.out.println(set); } Element String promise it a String, so complier will accept String Object 

Problem 3: Diese Symbole sind gleich, aber Sie können ihnen eine andere Spezifikation geben. Beispielsweise:

 public  void p(T t, E e) {} 

Problem 4: Sammlung erlaubt keine Typparameter-Kovarianz. Aber Array erlaubt Kovarianz.

Lassen Sie uns im Kontext der Java-Geschichte über sie sprechen;

  1. List :

Liste bedeutet, dass es ein beliebiges Objekt enthalten kann. List war in der Version vor Java 5.0; Java 5.0 führte die Liste aus Gründen der Abwärtskompatibilität ein.

 List list=new ArrayList(); list.add(anyObject); 
  1. List< ?> :

? bedeutet unbekanntes Objekt, kein Objekt; der Platzhalter ? Einführung ist zur Lösung des Problems von Generic Type gebaut; siehe Wildcards ; aber das verursacht auch ein anderes Problem:

 Collection< ?> c = new ArrayList(); c.add(new Object()); // Compile time error 
  1. List< T> List< E>

Bedeutet generische Deklaration unter der Prämisse None T oder E type in Ihrem Projekt Lib.

  1. List< Object> bedeutet generische Parametrisierung.

Du hast recht: String ist eine Teilmenge von Object. Da String “genauer” als Objekt ist, sollten Sie es so interpretieren, dass es als Argument für System.out.println () verwendet wird.

Theorie

String[] kann in Object[]

aber

List kann nicht in List .

Trainieren

Für Listen ist dies subtiler, da der Typ eines List-Parameters, der an eine Methode übergeben wird, bei der Kompilierung nicht überprüft wird. Die Methodendefinition könnte auch List< ?> Sagen – aus Sicht des Compilers ist sie äquivalent. Aus diesem Grund gibt das Beispiel 2 des OPs Laufzeiterrors und keine Kompilierungserrors.

Wenn Sie einen an eine Methode übergebenen List -Parameter sorgfältig behandeln, damit Sie keine Typüberprüfung für ein Element der Liste erzwingen, können Sie Ihre Methode mit List definieren, aber tatsächlich eine List akzeptieren List Parameter aus dem aufrufenden Code.

A. Also wird dieser Code keine Kompilierungs- oder Laufzeiterrors liefern und wird tatsächlich (und vielleicht überraschend?) functionieren:

 public static void test(List set) { List params = new List<>(); // This is a List params.addAll(set); // A String can be added to List params.add(new Long(2)); // A Long can be added to List System.out.println(params); } public static void main(String[] args) { List argsList = Arrays.asList(args); test(argsList); // The object passed is a List } 

B. Dieser Code gibt einen Laufzeiterrors:

 public static void test(List set) { List params = set; // Surprise! Runtime error set.add(new Long(2)); // Also a runtime error System.out.println(set); } public static void main(String[] args) { List argsList = Arrays.asList(args); test(argsList); } 

C. Dieser Code gibt einen Laufzeiterrors ( java.lang.ArrayStoreException: java.util.Collections$UnmodifiableRandomAccessList Object[] ):

 public static void test(Object[] set) { Object[] params = set; // This is OK even at runtime params[0] = new Long(2); // Surprise! Runtime error System.out.println(params); } public static void main(String[] args) { test(args); } 

In B ist der Parametersatz zum Zeitpunkt der Kompilierung keine typisierte List : Der Compiler sieht ihn als List< ?> . Es gibt einen Laufzeiterrors, da zur Laufzeit set das eigentliche Objekt wird, das von main() , und das ist eine List . Eine List kann nicht in List .

In C benötigt der Parametersatz ein Object[] . Es gibt keinen Kompilierungserrors und keinen Laufzeiterrors, wenn es mit einem String[] -Objekt als Parameter aufgerufen wird. Das liegt daran, dass String[] zu Object[] . Aber das tatsächliche Objekt, das von test() empfangen wurde test() bleibt ein String[] , es hat sich nicht geändert. Also wird das params -Objekt auch zu einem String[] . Und Element 0 eines String[] kann keinem Long zugewiesen werden!

(Hoffentlich habe ich hier alles richtig, wenn meine Argumentation falsch ist, bin ich mir sicher, dass die Gemeinde es mir erzählen wird.)