Java Generics Zusammenfassung

Einführung

Ich habe in den letzten Tagen erneut nach Generika gesucht. Nachdem ich einen kurzen Überblick über Generika gegeben hatte, beschloss ich, die folgenden beiden Inhalte als Memo zusammenzufassen.

Generika Übersicht

Wie auch immer, ich möchte die Vorteile der Verwendung von Generika neu organisieren. Es ** benachrichtigt Sie beim Kompilieren, wenn Sie versuchen, ein Objekt des falschen Typs ** einzufügen (zitiert aus Effective Java 3rd Edition, Kapitel 5, Generics). Infolgedessen kann eine ähnliche Verarbeitung mit verschiedenen Typen innerhalb des Bereichs realisiert werden, in dem die Typensicherheit garantiert werden kann. Jetzt möchte ich ein konkretes Beispiel im Code zeigen. Hier möchte ich Sequenzen und Generika vergleichen und die Güte des Schreibens in Generika erkennen. Schreiben Sie die Definition der Liste, das Hinzufügen zur Liste und das Abrufen aus der Liste, ohne die folgenden Generika zu verwenden.

ArrayList list = new ArrayList(); 
list.add("hoge"); 
String s = (String) list.get(0);

Da es als Objekttyp extrahiert wird, muss es explizit umgewandelt werden. Wenn ein Fehler auftritt (z. B. Zuweisen mit int und Extrahieren mit String), wird der Fehler erst bemerkt, wenn er verschoben wird. ← Das ist sehr schmerzhaft. Schreiben Sie die Definition der Liste mithilfe von Generika, das Hinzufügen zur Liste und das Abrufen wie folgt.

ArrayList<String> list = new ArrayList<String>(); 
list.add("hoge"); 
String s = list.get(0);

Beim Kompilieren wird eine Fehlermeldung angezeigt. (Sie können den Fehler bemerken, bevor Sie ihn ausführen ← Das ist sehr schön)

Über den Umfang von Generika

Generika hat zwei Bereiche. Methodenbereich und Instanzbereich. Für jeden wird eine Übersicht gegeben.

Methodenumfang

Zunächst wird die Syntax unten gezeigt.

SetInt.java


public class SetInt{
  public <E> Set<E> union(Set<E> s1,Set<E> s2){
    // (Beispiel)Verarbeitung zum Hinzufügen von s1 und s2
 }
}

Das erste, was Sie bemerken werden, ist das nach dem Zugriffsmodifikator public. Dies ist eine Typvariablendeklaration. Mit dieser Deklaration können wir eine Zuordnung definieren, dass das Argument und der Rückgabewert im Rahmen der Methode vom gleichen Typ sind. Die generische Deklaration im Methodenbereich kann nicht nur für Instanzmethoden, sondern auch für statische Methoden und Konstruktoren verwendet werden. Beim Aufrufen gibt es Fälle, in denen es so aufgerufen wird, wie es ist, und Fälle, in denen es durch explizite Angabe des Typs aufgerufen wird.

Beim Anrufen wie es ist
Set<Integer> result = SetInt.union(Set<Integer>,Set<Integer>);
Beim Aufruf durch explizite Angabe des Typs
Set<Integer> result = SetInt.<Integer>union(Set<Integer>,Set<Integer>);

Darüber hinaus kann der Typ explizit angegeben und die Ausnahmeverarbeitung wie folgt aufgerufen werden.

Hoge.java


public class Hoge{
	public <E extends Exception> void example() throws E {};
	public  void test() {
		try {
			this.<IOException>example();
		} catch (IOException e) {
			//Ausnahmebehandlung beim IOException-Ausnahmefang
		}
		try {
			this.<SQLException>example();
		} catch (SQLException e) {
			//Ausnahmebehandlung bei SQLException Exception Catch
		}
	}	
}

Instanzbereich

Es wird häufiger gesehen als der Methodenumfang, und ich bin der Meinung, dass es normalerweise in Einführungsbüchern behandelt wird. Ein Beispiel ist unten gezeigt.

Stack.java


public class Stack<E> {
  private E elements;
  public void push(E e) {
	//Prozess zum Verschieben auf Elemente
  }
  public E pop() {
	//Verarbeitung zum Extrahieren von E aus Elementen
  }
}

Sie können Zuordnungen definieren, bei denen die Argumente, Rückgabewerte und Instanzfeldtypen mehrerer deklarierter Instanzmethoden (zwei oben) identisch sind.

Geschichte um Typvariablen

Es wird davon ausgegangen, dass Sie Kenntnisse über "kovariante, antivariante, unveränderliche" und "Riskovs Ersatzprinzip" haben. Dieser Artikel ist über den ersteren leicht zu verstehen (https://www.thekingsmuseum.info/entry/2016/02/07/235454). In der folgenden Notiz gibt es als Beispiel Klassen A, B bzw. C, und es wird überprüft, dass sie eine Vererbungsbeziehung von C haben, die B erweitert, und B erweitert A.

Covariant

Es kann wie folgt definiert werden.

List<? extends B> extendsBList = new ArrayList<C>();

Der obige ExtendedAList hat die folgenden Eigenschaften.

  1. Variablen vom Typ B und C können aus extensBList extrahiert werden.
  2. In ExtendedBList kann nur der Typ Null gespeichert werden.

Abgesehen von Eigenschaft 1 bleibt Eigenschaft 2 fraglich. Der Prozess, durch den Eigenschaft 2 abgeleitet wird, ist unten zusammengefasst.

Warum kann ich in extensblist nichts anderes als den Nulltyp speichern?

Beispielsweise kann es in extensblist und extensblist.add (neues B ()) gespeichert werden. Bitte lesen Sie noch einmal den Initialisierungscode von extensblist. Initialisiert mit dem Typ ArrayList . Wenn B hinzugefügt werden könnte (), würde der Typ B zum Typ ArrayList hinzugefügt (), was einen Widerspruch verursacht. Daher kann in Liste <? Erweitert B> add () zu Liste und Liste hinzugefügt werden, die Liste <? Erweitert B> zugewiesen werden können, damit die Sicherheit des Typs nicht beeinträchtigt wird. Eine Einschränkung wird so platziert, dass nur neue Elemente hinzugefügt werden können (). Da es nur einen Nulltyp hat, gilt Eigenschaft 2.

Rebellion

Es kann wie folgt definiert werden.

List<? super B> superBList = new ArrayList<A>();

Die obige SuperBList hat die folgenden Eigenschaften.

  1. superBList kann Variablen vom Typ B und A speichern.
  2. Der aus superBList extrahierte Typ ist der Objekttyp.

Frage bleibt in Eigenschaft 2. Die Tatsache, dass Eigenschaft 1 gilt, bedeutet jedoch, dass das von get () abgerufene Objekt ein Objekttyp sein kann, der höher als der Typ B ist. Wenn <? Super B> gesetzt ist, kann das von get () erhaltene Objekt nur von dem Objekttyp empfangen werden, der sich oben in allen Typen befindet. Anstatt den Speicher zu akzeptieren, kann der zurückzugebende Typ nicht mehr angegeben werden.

Über PECS-Prinzipien

Effektive Java 2nd Edition Punkt 28 beschreibt die PECS-Prinzipien. Unten zitiert.

Wenn in der Funktion die Rolle des generischen Typarguments "Producer" lautet, wird use erweitert, und wenn es "Consumer" ist, verwenden Sie super. Ein Produzent ist ein Argument, das einen Wert in einer Funktion erzeugt (liefert). Andererseits ist ein Verbraucher ein Argument, das einen Wert in einer Funktion verbraucht (verwendet). Dieses Prinzip wird auch "PECS" genannt, kurz für Producer-Extends und Consumer-Super.

Anhand der Diskussion über Co-Change und Anti-Change können wir verstehen, warum wir dies tun. Nehmen Sie als Beispiel die Hoge-Klasse.

  • Um einen Wert von der Funktionsseite zu generieren (bereitzustellen), um den Wert von der Funktionsbenutzerseite zu erhalten, dh um den Wert abzurufen, verwenden Sie <? Extends Hoge>.
  • Auf der Funktionsseite bedeutet das Konsumieren (Verwenden) des Werts das Festlegen des Werts auf der Funktionsbenutzerseite, dh <? Super Hoge> beim Speichern des Werts.

In einer Methode kann die Verwendung von extens als Argument der Methode und super als Rückgabewert der Methode eine umfassendere Implementierung der Methode erfordern.

schließlich

Ich möchte von Zeit zu Zeit den Inhalt des Artikels überprüfen. Wenn ich Generika schreiben kann, möchte ich auch mit Generika entwerfen können.

Referenz

(https://www.amazon.co.jp/exec/obidos/ASIN/B078H61SCH/xray2000-22/)

Recommended Posts

Java Generics Zusammenfassung
[Java] Generika
Zusammenfassung des Java-Wissens
[Java] Generics-Beispiel
Java Generics (Hinweise)
Java-bezogene Zusammenfassung
Zusammenfassung des Java 8-Dokuments
Zusammenfassung des Java 11-Dokuments
Zusammenfassung der neuen Funktionen von Java 12
[Zusammenfassung] Zum Beispiel die Vorbereitung der Java-Umgebung
effektive Java 3. Zusammenfassung
Zusammenfassung der neuen Funktionen von Java 13
Häufig verwendete Java-Generika
Java statisch [Persönliche Zusammenfassung]
Thread sichere Zusammenfassung ~ Java ~
Zusammenfassung der primitiven Java-Spezialisierung
Zusammenfassung des Java-Entwicklungslinks
Persönliche Zusammenfassung über Java
Zusammenfassung der neuen Funktionen von Java 10
Zusammenfassung der regulären Ausdrücke von Java
Zusammenfassung der neuen Funktionen von Java 14
Zusammenfassung der Java-Unterstützung 2018
Zusammenfassung des Java-Entwurfsmusters
Java-Zusammenfassung für reservierte Wörter
Grobe Zusammenfassung des Java8-Streams
Was ist Java Assertion? Zusammenfassung.
[Java11] Stream-Zusammenfassung - Vorteile von Stream -
Progate Java (Anfänger) Review & Zusammenfassung
[Java] Generics-Klasse und Generics-Methode
[Java] Zusammenfassung der regulären Ausdrücke
[Java] Zusammenfassung der Operatoren (Operator)
Java8-Stream, Zusammenfassung des Lambda-Ausdrucks
Objektorientierte Zusammenfassung von Anfängern (Java)
Zusammenfassung
Java
Zusammenfassung der Grundlagen der Java-Sprache
Java-Tipps - Zusammenfassung der Federausführung
Zusammenfassung der Java Math Klasse
Java Generics T und? Unterschied
Java
[Java11] Stream Usage Summary -Basics-
[Java] Zusammenfassung der Steuerungssyntax
Zusammenfassung der Java-Fehlerverarbeitung
[Java] Zusammenfassung der Entwurfsmuster
[Java] Zusammenfassung der mathematischen Operationen
Berücksichtigung des Java Persistence Framework 2017 (Zusammenfassung) -1
[Für Anfänger] Zusammenfassung des Java-Konstruktors
Java-Veröffentlichungsdatum und EOL-Zusammenfassung
Zusammenfassung des Pakets [Java Silver Study]
Effektive Java 3rd Edition Kapitel 5 Generika
AtCoder 400 Punkte Algorithmus Zusammenfassung (Java Edition)
[Java] Versuchen Sie, mithilfe von Generika zu implementieren
Java Generics (definiert Klassen und Methoden)
Java "Pass by Reference" Problemzusammenfassung
Kotlin-Generika für Java-Entwickler
Java EE 8 (Jakarta EE 8) Zusammenfassung der neuen Funktionen
Zusammenfassung der objektorientierten Programmierung mit Java
Java lernen (0)
Java studieren ―― 3
[Java] -Array