> Verschiedene Arten verschachtelter Listen zulassen? " />
Mehrere Platzhalter bei generischen Methoden können den Java-Compiler verwirren
Das Problem:
Die Verwendung mehrerer Platzhalter bei Generische Methoden können sowohl beim Java-Compiler als auch beim Programmierer zu Verwirrung führen:
public class TwoListsOfUnknowns { static void doNothing(List<?> list1, List<?> list2) {} public static void main(String[] args) { List<String> list1 = null; List<Integer> list2 = null; doNothing(list1, list2); // compiles fine! } }
Zwei unabhängige Platzhalter können verwendet werden, um doNothing mit einem List
public class TwoListsOfUnknowns2 { static void doSomethingIllegal(List<?> list1, List<?> list2) { list1.addAll(list2); // DOES NOT COMPILE!!! } }
Dieses Verhalten ist zu erwarten, da list1 und list2 auf völlig unterschiedliche Typen verweisen.
Verwechslung entsteht mit dem folgenden Code:
public class LOLUnknowns1 { static void probablyIllegal(List<List<?>> lol, List<?> list) { lol.add(list); // this compiles!! how come??? } }
Dieser Code wird kompiliert, aber es ist möglich, eine List>-Liste zu haben. Sollte der folgende geänderte Code nicht kompiliert werden?
public class LOLUnknowns2 { static void rightfullyIllegal( List<List<? extends Number>> lol, List<?> list) { lol.add(list); // DOES NOT COMPILE! As expected!!! } }
Der Compiler scheint seinen Job zu machen, aber die Verwirrung besteht weiterhin mit der folgenden Variante:
public class LOLUnknowns3 { static void probablyIllegalAgain( List<List<? extends Number>> lol, List<? extends Number> list) { lol.add(list); // compiles fine!!! how come??? } }
Sollte dieser Code nicht kompiliert werden, da es sich möglicherweise um eine List> handelt ; lol und eine List
Um diese Verhaltensweisen zu verdeutlichen, vereinfachen wir den Code wieder auf LOLUnknowns1 und versuchen, „wahrscheinlichIllegal:“ aufzurufen, sogar mit demselben Typ für beide Platzhalter, der Code wird nicht kompiliert. Allerdings kompiliert ein Nulltyp für das erste Argument:
public class LOLUnknowns1a { static void probablyIllegal(List<List<?>> lol, List<?> list) { lol.add(list); // this compiles!! how come??? } public static void main(String[] args) { List<List<String>> lol = null; List<String> list = null; probablyIllegal(lol, list); // DOES NOT COMPILE!! } }
public class LOLUnknowns1b { static void probablyIllegal(List<List<?>> lol, List<?> list) { lol.add(list); // this compiles!! how come??? } public static void main(String[] args) { List<String> list = null; probablyIllegal(null, list); // compiles fine! } }
Die Verwirrung rührt von einem Missverständnis darüber her, was ein verschachtelter Platzhalter, wie z. B. List< ;Liste>>, bedeutet eigentlich. Java Generics ist invariant, was bedeutet, dass Beziehungen zwischen Typen für generische Instanziierungen nicht gelten. Dies gilt auch für verschachtelte Listen:
Daher ist eine Liste
A List<String> is (captureable by) a List<?>. A List<List<String>> is NOT (captureable by) a List<List<?>>. A List<List<String>> IS (captureable by) a List<? extends List<?>>.
List<List<?>> lolAny = new ArrayList<>(); lolAny.add(new ArrayList<Integer>()); lolAny.add(new ArrayList<String>());
Das Verhalten des Java-Compilers mit mehreren generischen Platzhaltern wird durch Capture-Konvertierungsregeln bestimmt. Um Verwirrung zu vermeiden, ist es wichtig, die Einschränkungen der Wildcard-Erfassung zu verstehen.
Das obige ist der detaillierte Inhalt vonWarum erlaubt eine List> verschiedene Arten verschachtelter Listen?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!