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.
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)
Generika hat zwei Bereiche. Methodenbereich und Instanzbereich. Für jeden wird eine Übersicht gegeben.
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
Set<Integer> result = SetInt.union(Set<Integer>,Set<Integer>);
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
}
}
}
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.
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.
Es kann wie folgt definiert werden.
List<? extends B> extendsBList = new ArrayList<C>();
Der obige ExtendedAList hat die folgenden Eigenschaften.
Abgesehen von Eigenschaft 1 bleibt Eigenschaft 2 fraglich. Der Prozess, durch den Eigenschaft 2 abgeleitet wird, ist unten zusammengefasst.
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
Es kann wie folgt definiert werden.
List<? super B> superBList = new ArrayList<A>();
Die obige SuperBList hat die folgenden Eigenschaften.
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.
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.
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.
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.
(https://www.amazon.co.jp/exec/obidos/ASIN/B078H61SCH/xray2000-22/)
Recommended Posts