[Java] Einführung in den Wildcard-Typ "Generics Boundary Wildcard"

Rolle des Wildcard-Grenztyps

Generische Java-Typen können keine List -Typen in List -Typen konvertieren.

Verschiedene Typen


//Wenn die Parameter vom Typ OK identisch sind
List<Integer> foo = new ArrayList<Integer>();

// NG List<Integer>Ist eine Liste<Number>Kann nicht konvertiert werden
List<Number> bar = foo;

//Ebenso ist eine Konvertierung auch bei NG-Initialisierung nicht möglich
List<Number> foo = new ArrayList<Integer>();

Daher können durch Verwendung des ** Boundary Wildcard-Typs ** ** Typparameter mit einer gewissen Breite ** deklariert werden. Es gibt jedoch zwei Arten von Grenz-Platzhaltertypen. Dies liegt daran, dass beim Festlegen der Typgrenzen in jeder Situation das Problem auftritt, dass das Verarbeitungssystem den Typ nicht festlegen kann. Schauen wir uns das Problem einzeln an.

Die folgende Fruchtklasse wird zur Erklärung verwendet.

Fruitクラス.png

Platzhaltertyp mit Obergrenze

Generic<? extends T>

Wenn Sie einen Typparameter wie oben angeben, ist der Typparameter ** Platzhaltertyp **. Der Typ ? Erweitert T </ kbd> bedeutet ** T oder einen Typ, der alle seine Unterklassen ** darstellt.

?_extends_fruit.png

Wenn Sie den Typ "List <? Extends Fruit>" verwenden, können Sie aus der ** Fruit-Klasse oder dem List-Typ ** konvertieren, der die Unterklassen angibt.

Liste der konvertierbaren Liste


List<? extends Fruit> basket = new ArrayList<Fruit>(); // 1
List<? extends Fruit> basket = new ArrayList<Melon>(); // 2
List<? extends Fruit> basket = new ArrayList<Lemon>(); // 3

Als nächstes sollten Sie Elemente aus der Variablen "List <? Extends Fruit>" abrufen. Bitte beachten Sie, dass die Korbvariable als Fruchtklasse abgerufen werden kann, unabhängig davon, ob es sich um 1, 2 oder 3 handelt.

Lesen

Konvertierung von "Limited Boundary Wildcard Type" in "T Class Type"

Ziehen Sie in Betracht, Elemente aus der Variablen "List <? Extends Fruit>" abzurufen. Bei einem Platzhaltertyp mit einer Obergrenze handelt es sich ** zumindest um einen Typ, der die T-Klasse und ihre Unterklassen darstellt **, sodass beim Abrufen eines Elements aus der Liste die Obergrenze T angegeben werden kann.

Konvertieren Sie den begrenzten Platzhaltertyp in den T-Typ


List<? extends Fruit> fruits = ...

//kein Problem
Fruit fruit = fruits.get(i);

Dies ist eine Konvertierung vom Typ "? Erweitert T" zum Typ "T".

Konvertierung vom "Wildcard-Typ der oberen Grenze" zum "Unterklassentyp von T"

Wenn Sie ein Element aus der Warenkorbvariablen abrufen, prüfen Sie, ob seine Unterklasse angegeben werden kann. Der Typ "List <? Extends Fruit>" kann aus mindestens den folgenden drei Listentypen konvertiert werden.

  1. ArrayList<Fruit>
  2. ArrayList<Melon>
  3. ArrayList<Lemon>

Daher ist es beim Abrufen eines Elements nicht möglich, eine Unterklasse anzugeben, die aus mehreren Serien stammt.

Der begrenzte Platzhaltertyp kann nicht in einen Unterklassentyp konvertiert werden


List<? extends Fruit> basket = ...

//NG-Kompilierungsfehler Kann nicht in Melonentyp konvertiert werden
Melon fruit = basket.get(i);

Wenn der Typ "? Extends Fruit" in eine Unterklasse konvertiert werden kann, treten die folgenden Inkonsistenzen auf.

Konvertieren Sie den gekappten Platzhaltertyp in den T-Unterklassentyp 1


//Machen Sie eine Melonenliste
List<Melon> melonList = new ArrayList<Melon>()
melonList.add(new Melon());

// List<Melon>Listentyp melonList<? extends Fruit>In Typ konvertieren
List<? extends Fruit> basket = melonList;

//Wenn es in eine Unterklasse konvertiert werden kann, kann es als Zitrone empfangen werden.
Lemon fruit = basket.get(i);

Daher ist eine Konvertierung in Unterklassen nicht zulässig. Daher ist eine Konvertierung vom Typ "Erweitert T" in den Typ "T" der Unterklasse "T" nicht möglich.

Schreiben

Als nächstes sollten Sie ein Element zur Variablen "List <? Extends Fruit> Früchte" hinzufügen. Da wir vom Typ "? Extends Fruit`" in den Typ "Fruit Type" konvertieren können, können wir der folgenden Fruchtvariablen anscheinend ein Fruit-Objekt hinzufügen.

Schreiben Sie in einen begrenzten Platzhaltertyp


List<? extends Fruit> fruits = new ArrayList<Fruit>();

//Scheint auf den ersten Blick möglich
fruits.add(new Fruit());

Wenn dies jedoch zulässig ist, treten die folgenden Inkonsistenzen auf.

Das Schreiben in einen begrenzten Platzhaltertyp ist inkonsistent


//Die Realität der Früchte ist eine Melonenliste
List<? extends Fruit> fruits = new ArrayList<Melon>();
//Die Zitronenklasse ist eine Unterklasse der Obstklasse
Fruit fruit = new Lemon();

//Zitrone kann zur Melonenliste hinzugefügt werden
fruits.add(fruit);

Daher ist es nicht möglich, vom Betontyp "T" oder "T-Unterklasse" in den Typ "Erweitert T" zu konvertieren. Dies bedeutet, dass Sie keine Elemente hinzufügen können, wenn Sie einen Listentyp mit einem begrenzten Platzhalter deklarieren. Hier kommt ein anderer Rand-Platzhaltertyp ins Spiel.

Platzhaltertyp mit Untergrenze

Generic<? super T>

Wenn Sie einen Typparameter wie oben angeben, handelt es sich um einen Platzhaltertyp mit einer Untergrenze. Der Typ ? Super T </ kbd> bedeutet ** T oder einen Typ, der alle seine Superklassen ** darstellt.

?_super_melon.png

Sie können von ** Fruchtklasse oder Listentyp ** in den Typ ** Liste \ <? Super Melon > ** konvertieren, dessen Typparameter die Fruchtklasse oder ihre Superklasse ist.

Liste der konvertierbaren Liste


List<? super Melon> baskets = new ArrayList<Melon>(); // 1
List<? super Melon> baskets = new ArrayList<Fruit>(); // 2
List<? super Melon> baskets = new ArrayList<Food>(); // 3
List<? super Melon> baskets = new ArrayList<Object>(); // 4

Dieses Mal werde ich zuerst darüber nachdenken, der Warenkorbvariablen Elemente hinzuzufügen. Bitte beachten Sie, dass die Melonenklasse zur Warenkorbvariablen hinzugefügt werden kann, wenn 1 bis 4 1, 2, 3 und 4 sind.

Schreiben

Konvertierung in einen Wildcard-Typ mit niedrigerer Grenze

Um ein Element zu einer "List <? Super Melon> -Korb" -Variablen hinzuzufügen, ist es im Fall eines Platzhaltertyps mit einer Untergrenze ** ein Typ, der mindestens eine T-Klasse oder eine höhere Superklasse darstellt **, also ein Element zu einem Listentyp Beim Hinzufügen sollten Sie in der Lage sein, die Untergrenze T anzugeben.

Überprüfen Sie anhand des Beispiels, ob Sie eine nach der anderen hinzufügen können.

Wenn List <? Super Melon> Früchte = new ArrayList <Object> ()

Zur Objektliste hinzufügen


// OK
fruits.add(new Melon())
// OK
fruits.add(new WaterMelon());

Wenn List <? Super Melon> Früchte = neue ArrayList <Food> ()

Zur Lebensmittelliste hinzufügen


// OK
fruits.add(new Melon())
// OK
fruits.add(new WaterMelon());

Wenn List <? Super Melon> Früchte = neue ArrayList <Melon> ()

Zur Melonenliste hinzufügen


// OK
fruits.add(new Melon());
// OK
fruits.add(new WaterMelon());

Mit anderen Worten, es ist möglich, von einem Typ "T" oder "T" in einen Typ "Super T" zu konvertieren.

Lesen

Der Typ ? Super Melon </ kbd> ist ein "Typ, der die Melonenklasse und alle ihre Superklassen darstellt". Außerdem erben alle Java-Klassen vom Typ ** Object **. Daher ist eine Konvertierung vom Typ "? Super T" in den Typ "Objekt" möglich.

Konvertierung vom Platzhaltertyp mit Untergrenze zum Objekttyp


Object object = basket.get(i)

Zusammenfassung

Appendix

Was es bedeutet, einen Wert mit einem Grenz-Platzhaltertyp zu schreiben

Möglicherweise haben Sie gehört, dass die Liste nicht geschrieben werden kann, wenn Sie einen begrenzten Platzhaltertyp mit einer oberen Grenze angeben.

Dies bedeutet einfach, dass Sie nicht:

** Kann nicht von "konkreter Typ" in "gekappten Platzhaltertyp" konvertiert werden **

Wenn Sie ein generisches Typobjekt mit einem Platzhalter für die obere Grenze deklarieren, erfolgt die obige Konvertierung, wenn Sie eine Funktion mit diesem Typparameter aufrufen.

Betrachten Sie die unten stehende Stack \ <T > -Klasse.

Stapelklasse


class Stack<T> {
    void push(T e) {}
}

Deklarieren Sie die Stack \ <T > -Klasse mit einem begrenzten Platzhaltertyp.

Stack<? extends Fruit> basket = new Stack<Fruit>();

Zu diesem Zeitpunkt ist der Typparameter T der Korbvariablen vom Typ "Extends Fruit". Die Push-Methode entspricht also:

Wenn der Stack-Typ-Parameter ein begrenzter Platzhalter ist


void push(`? extends Fruit` e) {}

Daher führt das Aufrufen dieser Push-Methode zu einer Konvertierung von einem "Obst" in einen "Extended Fruit" -Typ. Und diese Umwandlung ist NG.

//NG Fruchtart`? extends Fruit`Kann nicht in Typ konvertiert werden
basket.push(new Fruit()); 

Recommended Posts

[Java] Einführung in den Wildcard-Typ "Generics Boundary Wildcard"
[Java] Generika
Java Generics Zusammenfassung
Vorstellung der Bibliothek
[Java] Generics-Beispiel
Der in Java 10 eingeführte Schnittpunkttyp ist erstaunlich (?)
Java Generics (Hinweise)
[Java] Aufzählungstyp
Java Optionaler Typ
[Java] Achten Sie auf den Schlüsseltyp der Karte
Java-Doppeltyp
Informationen zur Bedeutung von Typvariablen, E, T usw., die in in Java verwendeten Generika verwendet werden
Organisiertes Memo im Kopf (Java - Datentyp)
Java getClass () ist nicht kompatibel mit Generika (oder Typvariablen).
[Java] Datentyp ①-Basistyp
Häufig verwendete Java-Generika
null gibt den Typ an
[Java, Kotlin] Typabweichung
Feld für den Java-Klassentyp
Typbestimmung in Java
Java # 1 studieren (typischer Typ)
[Java] Konvertierung des Datumstyps
Suchen Sie die Adressklasse und den Adresstyp aus der IP-Adresse mit Java
[Java] Um die Typinformationen der Typparameter zur Laufzeit zu kennen