Generika
Begrenzen Sie Elemente in einer Sammlung auf einen bestimmten Typ.
der Begriff
Ein paar Notizen:
Parametrisierte Typen und primitive Typen sind miteinander kompatibel
ArrayList Collection1 = New ArrayList <GanzEger> (); // Pass, keine WarningArrayList <Ganzzeit
Parametrisierte Typen berücksichtigen keine Vererbungsbeziehungen von Typparametern
ArrayList <string> collection3 = new ArrayList <Object> (); // Compilation überträgt nicht ArrayList <Obge
Aber
ArrayList Collection5 = New ArrayList <Ganzzahl> (); ArrayList <string> collection6 = collection5; // kompiliert von von
"?" Wildcard
"?" bedeutet jeden Typ. Verwenden Sie das "?" Wildcard -Zeichen, um sich auf verschiedene parametrisierte Typen zu beziehen. Es kann Methoden aufrufen, die sich nicht mit der Parametrisierung (z. B. Size () -Methode) beziehen, und keine Methoden aufrufen, die sich auf die Parametrisierung beziehen (z. B. add () Methode)
Wildcard -Erweiterung
Qualifizieren Sie die Obergrenze der Wildcard -Charaktere
ArrayList <? erweitert number> collection1 = new ArrayList <Ganzzahl> (); // compile durch ArrayList <? erweitert die Nummer> collection2 = new ArrayList <string> (); // kompilieren durch nicht
Qualifizieren Sie die untere Grenze der Wildcard -Charaktere
ArrayList <? Super Integer> Collection3 = New ArrayList <Nummer> (); // compile nach ArrayList <? Super Integer> Collection4 = New ArrayList <String> (); // kompilieren durch nicht
Benutzerdefinierte generische Methoden
C ++ - Vorlagenfunktionen
Vorlage <Klasse T> T add (t x, t y) {return (t) (x+y);}Java-Generika werden im Grunde genommen ausschließlich im Compiler implementiert, der vom Compiler verwendet wird, um Typprüfungen durchzuführen und Urteile zu tippen und dann gewöhnliche nicht generische Bytecode zu generieren. Diese Implementierungstechnik ist "Löschen".
"Erase" Instanz
Generika werden dem Javac -Compiler zur Verfügung gestellt, um den Eingangstyp der Sammlung zu definieren. Wenn der Compiler eine Sammlung mit Typbeschreibung kompiliert, werden die Informationen "Typ" entfernt.
public class generictest {public static void main (String [] args) {new GenerictEst (). testType (); } public void testType () {ArrayList <GanzEger> collection1 = new ArrayList <Integer> (); ArrayList <string> collection2 = new ArrayList <string> (); System.out.println (collection1.getClass () == Collection2.getClass ()); // Die Klassentypen der beiden sind gleich, dh der Bytecode ist das gleiche System.out.println (Collection2.getClass (). GetName ()); // Die Klasse ist java.util.arrayList, und es gibt keine tatsächlichen Parameterinformationen}}Ausgabe
WAHR
Java.util.ArrayList
Verwenden Sie Reflection, um den Compiler zu überspringen und andere Datenarten zu einer generischen Sammlung hinzuzufügen.
Nur Referenztypen können als tatsächliche Parameter für generische Methoden verwendet werden:
public class generictest {public static void main (String [] args) {SWAP (new String [] {"111", "222"}, 0,1); // kompilieren durch // Swap (new int [] {1,2}, 0,1); // Kompilieren Sie durch Kompilieren, weil int nicht der Referenztyp-Swap ist (neuer Integer [] {1,2}, 0,1); // kompilieren Sie durch}/*Swap die I-Th- und Jth-Elemente von Array a*/public static <t> void Swap (t [] a, int i, int j) {t temp = a [i]; a [i] = a [j]; a [j] = temp; }}Beachten Sie jedoch, dass Grundtypen manchmal als tatsächliche Parameter verwendet werden können, da automatische Packungen und Unboxen vorhanden sind. Beispiel (kompiliert und bestanden):
public class generictest {public static void main (String [] args) {new GenerictEst (). testType (); int a = Biggerone (3,5); // int und doppelt, den Austausch als Nummer nummer b = Biggerone (3,5,5); // String und int den Austausch als Objektobjekt c = Biggerone ("1", 2); } // y aus x, y public static <t> t Biggerone (t x, t y) {return y; }}Gleichzeitig zeigt dieses Beispiel auch, dass T, wenn die tatsächlichen Parameter inkonsistent sind, die Kreuzung, dh die erste gemeinsame übergeordnete Klasse, nimmt. Außerdem, wenn Sie Nummer b = Biggerone verwenden (3,5,5); zu String C = Biggerone (3,5,5); Dann wird der Kompilierungsfehler gemeldet:
Fehler: (17, 29) Java: Inkompatible Typen: Abgeleitete Typen erfüllen nicht die Obergrenze Inferenz: java.lang.number & java.lang.comparable <? erweitert java.lang.number & java.lang.lang.comparable <? >>
Obergrenze: Java.lang.String, Java.lang.Object
Aber es gibt eine Sache, die ich nicht verstanden habe. Ich bin Schritt-für-Schritt-Debugging in der Idee und stellte fest, dass das Ergebnis wie folgt ist: Generisches Debugging-Screenshot-1 Ich weiß nicht, warum B vom Typ Double ist (aber es wird einen Fehler erfassen, wenn er den Rückgabewert für Double B empfängt). Ich weiß nicht, ob es etwas mit der IDE zu tun hat. Zeigt die IDE beim Debuggen den genauesten Typ dieses Objekts an?
Typ -Inferenz der Typparameter
Der Prozess, nach dem der Compiler die tatsächlichen Typparameter einer generischen Methode beurteilt, wird als Typinferenz bezeichnet.
Wenn eine bestimmte Typvariable nur einer der Parameter und Rückgabewerte in der gesamten Parameterliste angewendet wird, wird sie basierend auf dem tatsächlichen Anwendungstyp zu diesem Zeitpunkt ermittelt, wenn die Methode aufgerufen wird. Das heißt, der Typ der generischen Parameter wird direkt anhand des Parametertyps oder des Rückgabewerts ermittelt, das übergeben wird, wenn die Methode aufgerufen wird. Zum Beispiel:
Swap (neue String [3], 1,2) -> statischer <e> void Swap (e [] a, int i, int j)
Wenn eine Typvariable an mehreren Stellen an allen Parametern und Rückgabewerte der gesamten Parameterliste angewendet wird. Wenn so viele tatsächliche Anwendungstypen beim Aufrufen der Methode demselben Typ entsprechen, ist der Typ des generischen Parameters dieser Typ. Zum Beispiel:
add (3,5) -> static <t> t add (t a, t b)
Wenn eine bestimmte Typvariable an vielen Stellen an allen Parametern und Rückgabetwerten der gesamten Parameterliste angewendet wird, dann, wenn die tatsächlichen Anwendungstypen an so vielen Orten beim Aufrufen der Methode unterschiedlichen Typen entsprechen, und es keinen Rückgabewert gibt, der maximale Schnitttyp zwischen den mehreren Parametern, dh der ersten gemeinsamen übergeordneten Klasse. Zum Beispiel:
FILL (New Integer [3], 3.5) -> statische <t> Hohlraumfüllung (t a [], t V)
Der tatsächliche entsprechende Typ dieses Beispiels ist die Anzahl, kompilierte und ausgeführte Probleme.
Wenn eine Typvariable an mehreren Stellen an allen Parametern und Rückgabewerte der gesamten Parameterliste angewendet wird. Wenn die tatsächlichen Anwendung an so vielen Stellen beim Aufrufen der Methode unterschiedlichen Typen entsprechen und ein Rückgabewert vorliegt, wird der Typ des Rückgabewerts Priorität angegeben, z. B.:
int x = add (3,3,5) -> static <t> t add (t a, t b)
Das obige Beispiel kompilierte Fehler, und der X -Typ wird in Schweben geändert, meldete auch einen Fehler, und die Änderung der Anzahl ist erfolgreich.
Beispiele für die Typinferenz von Parametertypen sind transitiv:
Copy (New Integer [5], neue String [5]) -> statische <t> void Copy (t [] a, t [] b)
Dieses Beispiel färbt sich, dass der tatsächliche Parametertyp Objekt ist und durchgesetzt wird.
Copy (New ArrayList <String>, New Integer [5]) -> statische <t> void Copy (Sammlung <T> A, T [] B)
In diesem Beispiel wird die Typ -Variable als Zeichenfolge direkt basierend auf der parametrisierten ArrayList -Klasseninstanz ermittelt und einen Fehler in der Kompilierung meldet.
Benutzerdefinierte generische Klassen
Beispiel
public class genericdao <t> {public void add (t x) {} public t findById (int id) {return null; } public void delete (t obj) {} public void delete (int id) {} public void update (t obj) {} public t findByusername (String name) {return null; } public <T> set <T> findByConditions (String WHERE) {return null; }}HINWEIS: Wenn eine Variable als Generikum deklariert wird, kann sie nur durch Instanzvariablen und -Methoden (und eingebettete Typen) aufgerufen werden, jedoch nicht durch statische Variablen und statische Methoden. Da statische Mitglieder von parametrisierten Klassen geteilt werden, sollten statische Mitglieder keine Typ-Parameter auf Klassenebene haben.
Vergleich generischer Methoden und generischer Klassen
Beispiel:
public class a <t> () {// Mitgliedsmethode der generischen Klasse, das T wird beschränkt, indem T nach einem öffentlichen t memberfunc () {return null; } // Generische Methode, hier t und t unterscheiden sich von t der öffentlichen statischen statischen Klasse A <t> t GenericFunc (t a) {return null; } public static void main (String [] args) {// kompiliert ohne bestanden // Integer i = a <string> (). findByUnername ("s"); // kompiliert von set <GeNeger> set = a <string> (). FindByConditions ("S"); }}Hier Integer i = a <string> (). FindByUnername ("S"); Kompiliert und meldet einen Fehler:
Fehler: (35, 61) Java: Inkompatibler Typ: Java.lang.String kann nicht in java.lang.Integer konvertiert werden
Aus diesem Beispiel ist ersichtlich, dass das t der generischen Methode und die t der Klasse A unterschiedlich sind.
Generika und Überlegungen
Erhalten Sie die tatsächlichen Typparameter eines Generikums durch Reflexion
Verwenden Sie generische Variablen als Parameter der Methode und verwenden Sie die Methode GetGenericParameterTypes der Methodenklasse, um den tatsächlichen Typ -Parameterbeispiel des Generikums zu erhalten:
public class generictest {public static void main (String [] args) löst eine Ausnahme aus {getParamType (); } /*Verwenden Sie die Reflexion, um den tatsächlichen Parameter -Typ der Methodenparameter zu erhalten. // den Typ der generischen Parameter des Methodentyps [] type = methode.getgenericParameterTypes () abrufen; System.out.println (Typen [0]); // Parametrisierte Typ parameterizedtype pType = (parameterizedtype) Typen [0]; // Primitive Typ System.out.println (pType.getrawType ()); // tatsächlicher Typ Parameter system.out.println (pType.getactualtTypeRGUTUMEN () [0]); System.out.println (pType.getactualtTypePearGumente () [1]); } /* Methode zum Testen von Parametertypen* / public static void applyMap (MAP <Integer, String> MAP) {}}Ausgangsergebnis:
java.util.map <java.lang.ineger, java.lang.string> interface java.util.mapclass java.lang.Tinegerclass java.lang.string