Frage Unterschied zwischen unbeschränkter Erstellung und beschränktem Wildcard-Array?


Warum ist dieser Code gültig?

ArrayList<?>[] arr = new ArrayList<?>[2];

aber die folgenden zwei sind nicht?

ArrayList<? extends Object>[] arr = new ArrayList<? extends Object>[2];
ArrayList<? super Object>[] arr = new ArrayList<? super Object>[2];

Die zwei letzten Zeilen erzeugen den Kompilierfehler;

Fehler: Generische Array-Erstellung.

Bitte klären Sie den Unterschied.

aktualisieren

Andererseits ArrayList<?>[] arr = new ArrayList<?>[2]; Kompiliert gut aber

ArrayList<?> arr = new ArrayList<?>();

nicht.


9
2017-10-01 10:54


Ursprung


Antworten:


Es gibt ein paar Probleme hier, schauen wir uns nacheinander an:

  1. Ein Typ gebunden (dh extends Object) kann nur deklariert werden, wenn ein Typ deklariert wird, er kann nicht verwendet werden, wenn ein Objekt instanziiert wird.

    beispielsweise

    ArrayList<? extends Object> ab = new ArrayList<? extends Object>(); // error ArrayList<? extends Object> ac = new ArrayList<String>(); // okay

  2. Arrays unterstützen keine Typparameter, zum Beispiel:

    List<Integer>[] arrayOfLists = new List<Integer>[2]; // compile time error List<Integer> list = new List<Integer>(); // okay

    Oracle dokumentiert die Gründe für diese Einschränkung Hier.

  3. <?> kann bei der Deklaration eines Typparameters und bei Arrays verwendet werden. Es wurde hinzugefügt, um "unchecked exception" -Fehler zu vermeiden, wenn Java-Code gemischt wird, der Generics verwendet und nicht verwendet. Es bedeutet "unbekannter generischer Typ". Mehr Details zu unbegrenzten Wildcards Hier.

    ArrayList<?>[] arr = new ArrayList<?>[2];

    ist aus den oben genannten Gründen gültig. Es ist jedoch von sehr begrenzter Verwendung, da nur null Typen zugeordnet werden können, die als deklariert sind <?>.

    arr[0] = null; // compiles

    arr[1] = new Object(); // compile time error

    Oracle bietet Folgendes an Anleitung zur Verwendung von Platzhaltern was hilft zu verstehen, wann man diese Joker benutzt.

  4. <?> kann nicht zum Instanziieren eines Objekts verwendet werden. Beispielsweise

    ArrayList<?> arr = new ArrayList<?>(); // does not compile

    ArrayList<?> arr2 = new ArrayList<>(); // but this does

    ArrayList<?> arr3 = new ArrayList<String>(); // and so does this

    Allerdings hat man immer noch das Problem, dass man benutzt <?> akzeptiert nur null.

    arr3.add( " " ); // does not compile even though it was instantiated with String

    arr3.add( null ); // compiles just fine


13
2017-10-01 12:09



Sie müssen zuerst verstehen, warum das Erstellen eines Arrays eines parametrisierten Typs nicht zulässig ist. Das liegt daran, dass Arrays zur Laufzeit prüfen, ob es sich bei den eingefügten Elementen um Instanzen des Komponententyps handelt (a la instanceof). Es ist nicht möglich zu überprüfen instanceof ein parametrisierter Typ, weil ein Objekt keinen Sinn für den Typparameter hat, mit dem es erstellt wurde. instanceof ArrayList<Integer> ist in Java illegal, so etwas wie instanceof ArrayList<? extends Number>, aber instanceof ArrayList<?> ist in Java erlaubt, da es keine Informationen über den Typparameter des Objekts benötigt. (Apropos instanceof ArrayList<? extends Object> und instanceof ArrayList<? super Object> sind auch illegal.)

Konzeptionell ArrayList<? extends Object> ist fast vollständig identisch mit ArrayList<?> (Es gibt kleinere Unterschiede, aber nicht relevant), aber für die Konsistenz der Grammatik, new ArrayList<? extends X>[...] ist für kein X erlaubt.


3
2017-10-02 10:27