Seit dem Aussehen der Java-Sprache hat sich durchgemachtviele Änderungen, die zweifellos positive Momente zu seiner Funktionalität gebracht haben. Eine solche bedeutsame Änderung ist die Einführung von Java Generic oder Generalisierung. Diese Funktionalität hat die Sprache nicht nur flexibler und vielseitiger gemacht, sondern auch viel sicherer in Bezug auf die Reduzierung von Datentypen.

Java Generika Beschreibung

Tatsache ist, dass vor der Einführung von generischen GenerikaCode in Java könnte nur durch Bezugnahme auf den Objekttyp erstellt werden. Solche Links können jedem Objekt zugewiesen werden. Schließlich sind alle Klassen in Java implizite Nachkommen der Object-Klasse. Dieser Ansatz ist jedoch eine potenzielle Quelle für viele Sicherheitsfehler, wenn Sie ein Objekt explizit von Object in den Zieltyp konvertieren. Wenn Verallgemeinerungen verwendet werden, werden alle Umwandlungen implizit und automatisch durchgeführt, was sogar das Auftreten von Fehlern ausschließt.

Java Generics: Beschreibung und Beispiel

Nehmen wir ein einfaches Beispiel für die Anwendung der Generalisierung auf die übliche Klasse in der folgenden Abbildung. Und erst dann werden wir uns mit allen Feinheiten und Nuancen von Java Generic auseinandersetzen.

generische Klasse Java

Beachten Sie, wie diePair-Class-Ankündigung. Direkt nach dem Klassennamen werden die spitzen Klammern geöffnet, in denen der Buchstabe T angezeigt wird, eine Art Platzhalter, der beim Erstellen einer Instanz dieser Klasse durch einen bestimmten Typ ersetzt wird. Es sieht so aus: Paar <Ganzzahl> obj = neues Paar <Ganzzahl> (). Es sollte beachtet werden, dass Sie anstelle von T einen beliebigen Buchstaben angeben können, aber in der Regel T, V oder E verwenden.

Hinweis: Beginnend mit der achten Version von Java, die den Zieltyp angibt, wenn die Verknüpfung deklariert wird, können Sie die spitzen Klammern im Konstruktor leer lassen. Also kann das obige Beispiel wie folgt umgeschrieben werden: Paar <Integer> obj = neues Paar <> ().

Wenn eine Klasse auf diese Weise deklariert wird, dann in ihrerSie können diesen Buchstaben anstelle von spezifischen Feldtypen, Referenzen und Methoden verwenden, die von Methoden zurückgegeben werden. Da T beim Erstellen des Klassenobjekt von einem bestimmten Typ, erste und zweite Felder in diesem Fall sein werden, von dem Typ Integer ersetzt wird.

Nach der Logik folgen die Argumente firstItem und secondItem,an den entsprechenden Konstruktor übergeben, muss auch vom Typ Integer oder dessen Unterklasse sein. Wenn Sie versuchen, einen anderen Datentyp als den beim Erstellen des Objekts angegebenen zu übergeben, überspringt der Compiler diesen Fehler nicht. Der Konstruktor mit den Argumenten beim Erstellen des Objekts hat also die folgende Form: Paar <Ganzzahl> obj = neues Paar <> (neue Ganzzahl (1), neue Ganzzahl (2)). Gleiches gilt für die Argumente der setFirst- und setSecond-Methode. Und wie Sie wahrscheinlich schon erraten haben, geben die Methoden getFirst und getSecond Werte vom Typ Integer zurück.

Eine generische Klasse mit mehreren Typparametern

In generischen Klassen können Sie auch mehrere Typparameter angeben, die in spitzen Klammern durch Kommas getrennt angegeben werden. Die Pair-Klasse für diesen Fall ist in der folgenden Abbildung dargestellt.

Java generisch

Wie Sie sehen, wenn Sie eine Instanz einer solchen Klasse erstellenIn den spitzen Klammern müssen Sie die gleiche Anzahl von Typen wie die Parameter angeben. Wenn Sie mit einer solchen Datenstruktur wie Map vertraut sind, werden Sie vielleicht feststellen, dass dort das gleiche Prinzip verwendet wird. Dort bestimmt das erste Argument den Typ des Schlüssels und der zweite - den Typ des Wertes. Es sollte beachtet werden, dass die Arten von Argumenten, die an die Objekterstellung übergeben werden, dieselben sein können. Daher ist die folgende Deklaration einer Instanz der Pair-Klasse absolut korrekt: Pair <String, String> obj.

Einige Merkmale von Verallgemeinerungen

Bevor weiter fortgefahren wird, sollte beachtet werden, dassDer Java-Compiler erstellt keine anderen Versionen der Pair-Klasse. Tatsächlich werden während des Kompilierungsprozesses alle Informationen über den generischen Typ gelöscht. Stattdessen werden die entsprechenden Typen umgewandelt, wodurch eine spezielle Version der Klasse Pair erstellt wird. Das Programm selbst hat jedoch immer noch eine einzige verallgemeinerte Version dieser Klasse. Dieser Prozess wird im Java-Generic-Typ-Cleaning aufgerufen.

Lassen Sie uns einen wichtigen Punkt beachten. Verweise auf verschiedene Versionen derselben generischen Java-Klasse können nicht auf dasselbe Objekt verweisen. Das heißt, wir haben zwei Links: Pair <Integer> obj1 und Pair <Double> obj2. Daher tritt ein Fehler in der Zeile obj1 = obj2 auf. Obwohl beide Variablen vom Typ Paar <T> sind, unterscheiden sich die Objekte, auf die sie sich beziehen. Dies ist ein anschauliches Beispiel für die Sicherheit von Typen in Java Generic.

Einschränkungen für verallgemeinerte Klassen

Es ist wichtig zu wissen, dass Verallgemeinerungen angewendet werden könnennur zu Referenztypen, dh das an den Parameter generische Klasse übergebene Argument muss ein Klassentyp sein. Solche einfachen Typen wie beispielsweise Double oder Long können nicht übertragen werden. Mit anderen Worten, die folgende Zeile der Paarklassen-Deklaration ist nicht gültig: Paar <int> obj. Diese Einschränkung ist jedoch kein ernsthaftes Problem, da Java für jeden primitiven Typ eine entsprechende Wrapper-Klasse besitzt. Streng genommen, wenn die Klasse Pair wollen Sie eine ganze Zahl und Boolescher Wert avtoupakovka einzukapseln tut alles für Sie: Pair <Integer, Boolean> obj = new Pair <> (25, true).

Eine weitere ernsthafte Einschränkung ist dieUnmöglichkeit, eine Instanz eines Typparameters zu erstellen. Die folgende Zeile verursacht daher einen Kompilierungsfehler: T first = new T (). Dies ist offensichtlich, da Sie nicht im Voraus wissen, ob eine vollständige Klasse oder eine abstrakte Schnittstelle als Argument übergeben wird. Dasselbe gilt für die Erstellung von Arrays.

Begrenzte Arten

Oftmals gibt es Situationen, in denenEs ist notwendig, die Liste der Typen zu begrenzen, die als Argument an die generische Java-Klasse übergeben werden können. Nehmen wir an, dass wir in unserer Pair-Klasse ausschließlich numerische Werte für weitere mathematische Operationen einkapseln wollen. Um dies zu tun, müssen wir die obere Grenze des Typs Parameter festlegen. Dies wird mithilfe einer Superklassen-Deklaration implementiert, die von allen Argumenten übernommen wird, die in spitzen Klammern übergeben werden. Es sieht so aus: Klasse Pair <T extends Number>. Auf diese Weise lernt der Compiler, dass Sie anstelle des T-Parameters entweder die Number-Klasse oder eine ihrer Unterklassen ersetzen können.

Dies ist eine übliche Technik. Solche Einschränkungen werden häufig verwendet, um die Kompatibilität von Typparametern in derselben Klasse sicherzustellen. Betrachten Sie ein Beispiel für unsere Pair-Klasse: class Pair <T, V extends T>. Hier sagen wir dem Compiler, dass Typ T beliebig sein kann, und Typ V muss entweder Typ T oder eine seiner Unterklassen sein.

Die Einschränkung "von unten" tritt genau gleich aufBild, aber anstelle des Wortes erstreckt sich das Wort super geschrieben. Das heißt, die Deklaration der Klasse Pair <T super ArrayList> gibt an, dass anstelle von T entweder eine ArrayList oder eine Klasse oder Schnittstelle, die sie erbt, ersetzt werden kann.

Generische Java-Methoden und -Konstruktoren

In Java können Verallgemeinerungen nicht nur in Bezug auf Klassen, sondern auch auf Methoden angewendet werden. So kann die verallgemeinerte Methode in der normalen Klasse deklariert werden.

generische Java-Methoden

Wie Sie in der obigen Abbildung sehen können, ist die Deklaration der verallgemeinerten Methode nicht kompliziert. Es ist ausreichend, spitze Klammern vor der Rückgabetyp-Methode zu setzen und Typparameter in ihnen anzugeben.

Im Fall des Konstruktors wird alles auf die gleiche Weise gemacht:

Java generische Art der Reinigung

Spitze Klammern stehen in diesem Fall vor dem Namen des Konstruktors, da dieser keinen Wert liefert. Das Ergebnis der Arbeit beider Programme wird sein:

Ganzzahl

Zeichenfolge