Was ist Generics in Java?

Generics in Java wurde bereits 2004 als neues Feature der Java-Programmiersprache eingeführt und war Teil der JDK 5-Version. Es wird am häufigsten zusammen mit dem Java Collections Framework verwendet. Ab heute ist es eines der bekanntesten und gefragtesten Features der Java-Programmiersprache.

Generisches Java wurde 1998 von vier Personen gefunden, nämlich Gilad Bracha, Martin Odersky, David Stoutamire und Philip Wadler. Es war eine Erweiterung der Java-Sprache, die generische Typen unterstützte. Es sollte zwei Hauptziele erreichen:

  1. Geben Sie Sicherheit
  2. Wiederverwendbarkeit des Codes

Definition von Generika in Java

Generics können definiert werden, um die Wiederverwendbarkeit von Code zu erreichen, indem generische Klassen, Interfaces, Konstruktoren und Methoden definiert werden, die mit verschiedenen Datentypen verwendet werden können. Außerdem wird die Typensicherheit erreicht, indem der in der Implementierung verwendete Datentyp deklariert und somit beseitigt wird die Chancen eines Laufzeitfehlers.

Wie werden Generika in Java implementiert?

Generika werden mit spitzen Klammern "" implementiert. Die Klammern enthalten den Typparameter „T“. Beispiel. Der Typparameter „T“ ist ein Platzhalter, der angibt, dass ihm zur Laufzeit ein Datentyp zugewiesen wird. Beispielsweise wird eine generische Klasse definiert als:

public class MyGenericClass (…)

Im Folgenden sind die Standardtypparameter aufgeführt:

  • T: Typ
  • E: Element
  • N: Nummer
  • K: Schlüssel
  • V: Wert

S, U, V usw. werden verwendet, um den zweiten, dritten und vierten Parameter zu definieren, falls Mehrfachparameter verwendet werden.

Grundlegendes zu Generics in Java

Inzwischen fragen Sie sich vielleicht, was Typensicherheit ist und wie sie funktioniert. Oder wie unterscheiden sich generische Klassen, Interfaces, Konstruktoren und Methoden von unseren regulären Klassen und Methoden, die sie wiederverwendbar machen? Lass es uns herausfinden.

Java ist eine statisch typisierte Sprache, bei der Sie den „Typ“ deklarieren müssen, der dem Datentyp des Werts entspricht, der von der Variablen gespeichert wird, bevor Sie sie verwenden.

Beispiel: String myString =”eduCBA”;

Hier ist "String" der Datentyp, "myString" die Variable, die einen Wert enthält, dessen Typ "String" ist.

Wenn Sie nun versuchen, einen Booleschen Wert anstelle einer Zeichenfolge zu übergeben, Beispiel:

String myBooleanStr = true;

Beim Kompilieren wird sofort ein Fehler angezeigt, der besagt, dass "Typenkonflikt: Konvertierung von Boolean nach String nicht möglich".

Wie erreichen wir die Wiederverwendbarkeit von Code mit Generika?

Definieren wir nun eine reguläre Methode:

public static void welcome(String name)(
System.out.println("welcome to " + name);
)

Diese Methode kann nur durch Übergeben eines Zeichenfolgenparameters aufgerufen werden. Beispielsweise:

welcome(“eduCBA”);

Die Ausgabe wird "Willkommen bei eduCBA" sein.

Sie können diese Methode jedoch nicht aufrufen, indem Sie andere Datentypen wie Integer oder Boolean umgehen. Wenn Sie dies versuchen, wird beim Kompilieren eine Fehlermeldung angezeigt, die besagt, dass die Methode welcome (String) vom Typ Runner für die Argumente (boolean) nicht anwendbar ist. Das heißt, Sie können keinen anderen Datentyp an eine Methode übergeben, die nur einen String als Parameter akzeptiert.

Dies bedeutet auch, wenn Sie eine ähnliche Methode für einen anderen Datentyp aufrufen möchten, müssen Sie eine neue Methode schreiben, die den erforderlichen Datentyp als Parameter akzeptiert. Diese Funktion zum erneuten Schreiben von Methoden mit Parametern unterschiedlicher Datentypen wird auch als Methodenüberladung bezeichnet. Der Hauptnachteil davon ist, dass es die Größe Ihres Codes erhöht.

Wir könnten jedoch auch Generics verwenden, um die obige Methode neu zu schreiben und für jeden von uns benötigten Datentyp zu verwenden.

Definieren einer generischen Methode:

public static void welcome(T t)(
System.out.println("it is " + t);
)

Hinweis : Hier ist „t“ ein Objekt vom Typ T. T wird der Datentyp zugewiesen, der zum Aufrufen der Methode verwendet wird.

Jetzt können Sie diese Methode wiederverwenden, indem Sie sie bei Bedarf für eine Zeichenfolge oder einen Booleschen Wert, eine Ganzzahl oder einen anderen Datentyp aufrufen.

welcome("educate");
Integer Myint = 1;
welcome(Myint)
welcome(true);

Die obigen Anweisungen liefern die folgende Ausgabe:

Es ist Educa
Es ist 1
Das ist wahr

Daher können wir durch die Verwendung von Generika hier unsere Methode für verschiedene Datentypen wiederverwenden.

Wie erreichen wir die Typensicherheit mit Generika?

Einer der Hauptunterschiede zwischen Arrays und Collection besteht darin, dass Arrays nur homogene Daten speichern können, während Collections heterogene Daten speichern können. Das heißt, Sammlungen können alle benutzerdefinierten Datentypen / Objekte speichern.

HINWEIS: Sammlungen können nur Objekte (benutzerdefinierter Datentyp) und keinen primitiven Datentyp enthalten. Um mit primitiven Daten zu arbeiten, verwenden Typauflistungen Wrapperklassen.

Betrachten wir nun eine ArrayList.

ArrayList myList = new ArrayList();

Fügen wir dem ArrayList-Objekt Daten vom Typ String, Integer und Double hinzu.

myList.add("eduCBA");
myList.add(1);
myList.add(5.2);

Beim Drucken des ArrayList-Objekts sehen wir, dass es die folgenden Werte enthält: (eduCBA, 1, 5.2).

Wenn Sie diese Werte nun in Variablen abrufen möchten, müssen Sie sie typisieren.

String someStr = (String)myList.get(0);
Integer someInt = (Integer)myList.get(1);
Double someFlt = (Double)myList.get(2);

Wenn Sie keine Typumwandlung durchführen, wird beim Kompilieren ein Fehler mit der Meldung "Typinkonflikt: Konvertierung von Objekt in Zeichenfolge nicht möglich" angezeigt.

Daraus können Sie schließen, dass Sie beim Abrufen der Objekte aus Ihrer ArrayList eine Typumwandlung in die entsprechenden Typen vornehmen müssen. Die Frage, die sich hier stellt, ist, woher Sie wissen, für welchen Datentyp er typisiert werden soll. In Echtzeit enthält Ihre ArrayList Tausende von Datensätzen, und die Typisierung in verschiedene Datentypen für jedes einzelne Objekt ist keine Option. Möglicherweise führen Sie eine Typumwandlung mit dem falschen Datentyp durch. Was passiert dann?

Dieses Mal wird kein Fehler bei der Kompilierung angezeigt, sondern ein Laufzeitfehler mit der Angabe "Ausnahme im Thread" main " .main (Runner.java:43) ”.

Da wir nicht garantieren können, welche Art von Daten in einer Sammlung vorhanden sind (in diesem Fall ArrayList), werden sie hinsichtlich des Typs als nicht sicher betrachtet. Hier kommen Generika ins Spiel, um die Typensicherheit zu gewährleisten.

Verwenden von ArrayList mit Generics:

ArrayList myList = new ArrayList();

Beachten Sie, dass in eckigen Klammern "" der Typ "String" angegeben ist. Dies bedeutet, dass diese spezielle Implementierung von ArrayList nur Daten vom Typ "String" enthalten kann. Wenn Sie versuchen, einen anderen Datentyp hinzuzufügen, wird einfach ein Kompilierungsfehler ausgegeben. Hier haben Sie Ihre ArrayList typsicher gemacht, indem Sie die Möglichkeit eliminiert haben, einen anderen Datentyp als "String" hinzuzufügen.

Nachdem Sie den Datentyp festgelegt haben, der mithilfe von Generika zu Ihrer Sammlung hinzugefügt werden darf, müssen Sie ihn beim Abrufen Ihrer Daten nicht mehr typisieren. Das heißt, Sie können Ihre Daten einfach abrufen, indem Sie Folgendes schreiben:

String someStr = myList.get(0);

Wie vereinfacht Generics in Java die Arbeit?

Es hilft dabei, Ihre Sammlungen typsicher zu machen, und stellt so sicher, dass Ihr Code zu einem späteren Zeitpunkt nicht aufgrund einer Laufzeitausnahme ausfällt. Außerdem muss der Codierer nicht jedes Objekt in der Sammlung typisieren, wodurch die Codeentwicklung schneller und einfacher wird. Durch die Verwendung von generischen Klassen und Methoden kann der Code bei der Implementierung auch gemäß dem jeweils erforderlichen Datentyp wiederverwendet werden.

Was können Sie mit Generics in Java noch tun?

Bisher haben wir gesehen, wie wir mit Generika Typensicherheit und Wiederverwendbarkeit von Code erreichen können. Lassen Sie uns nun einen Blick auf die anderen Funktionen werfen, die Generika bieten. Sie sind:

  1. Begrenzte und mehrfach begrenzte Typen
  2. Geben Sie Platzhalter ein

Eingeschränkter Typ: Bei einem eingeschränkten Typ ist der Datentyp eines Parameters an einen bestimmten Bereich gebunden. Dies wird mit Hilfe des Schlüsselworts "extend" erreicht.

Betrachten wir zum Beispiel eine generische Klasse mit einem begrenzten Typparameter, der die Runnable-Schnittstelle erweitert:

class myGenericClass()

Jetzt, während Sie das Objekt in einer anderen Klasse erstellen:

myGenericClass myGen = new myGenericClass();

Die obige Anweisung wird einwandfrei und fehlerfrei ausgeführt. Das heißt, im Fall des begrenzten Typs können Sie denselben Klassentyp oder seinen untergeordneten Klassentyp übergeben. Außerdem können Sie den Parametertyp beim Aufrufen an eine Schnittstelle binden und deren Implementierungen übergeben, wie im obigen Beispiel.

Was passiert, wenn Sie versuchen, einen anderen Parametertyp zu verwenden?

myGenericClass myGen = new myGenericClass();

In dem obigen Fall erhalten Sie eine Fehlermeldung zur Kompilierungszeit, die besagt, dass "Bound mismatch: Der Typ Integer ist kein gültiger Ersatz für den Typecast vom Typ myGenericClass".

Mehrfach begrenzte Typen: Bei Mehrfach begrenzten Typen können wir den Parameterdatentyp an mehrere Typen binden. Beispielsweise,

Class myGeneric()

In diesem Fall können Sie einen beliebigen Typ übergeben, der die Number-Klasse erweitert und die Runnable-Schnittstelle implementiert. Wenn Sie jedoch mehrere beschränkte Typen verwenden, sollten Sie Folgendes beachten:

  1. Wir können nicht mehr als eine Klasse gleichzeitig verlängern.
  2. Wir können eine beliebige Anzahl von Schnittstellen gleichzeitig erweitern, ohne dass es eine Beschränkung für Schnittstellen gibt.
  3. Der Klassenname sollte immer an erster Stelle stehen, gefolgt vom Schnittstellennamen, wenn dies nicht der Fall ist, führt dies zu einem Fehler bei der Kompilierung.

Typ Wildcards: Sie werden durch ein Fragezeichen (?) Dargestellt. Es werden zwei Hauptschlüsselwörter verwendet:

Erweitert (um obere Schranke zu definieren) und Super (um untere Schranke zu definieren).

Beispielsweise,

ArrayList al

Dieses ArrayList-Objekt "al" enthält alle Daten des Typs T und alle seine Unterklassen.

ArrayList al

Dieses ArrayList-Objekt "al" enthält alle Daten des Typs T und alle seine Oberklassen.

Vorteile von Generika in Java

1. Flexibilität : Generics bietet unserem Code die Flexibilität, mithilfe generischer Klassen und Methoden verschiedene Datentypen zu berücksichtigen.

2. Pflege und Wiederverwendbarkeit des Codes: Aufgrund generischer Klassen und Methoden muss der Code nicht neu geschrieben werden, falls sich die Anforderungen zu einem späteren Zeitpunkt ändern, um die Pflege und Wiederverwendung des Codes zu vereinfachen.

3. Typensicherheit: Bietet Typensicherheit für das Auflistungsframework, indem der Datentyp, den die Auflistung enthalten kann, im Voraus definiert und das Risiko von Fehlern zur Laufzeit aufgrund von ClassCastException beseitigt wird.

4. Vermeiden von Typumwandlungen: Da die Datentypen, die in den Sammlungen gespeichert sind, bereits festgelegt sind, müssen Sie sie zum Zeitpunkt des Abrufs nicht typumwandeln. Dies verringert die Länge des Codes und verringert auch den Aufwand eines Codierers.

Generika in Java-Kenntnissen

Um mit Generics arbeiten zu können, sollten Sie mit den Grundlagen von Java vertraut sein. Sie sollten verstehen, wie die Typprüfung und das Typgießen funktionieren. Gründliche Kenntnisse anderer Konzepte wie Methodenüberladung, Beziehung zwischen Eltern- und Kindklassen, Schnittstellen und deren Implementierungen sind erforderlich. Das Verständnis des Unterschieds zwischen primitiven Datentypen (systemdefinierter Datentyp) und Objekten (benutzerdefinierter Datentyp) ist für die Arbeit mit dem Erfassungsframework von entscheidender Bedeutung.

Warum sollten wir Generics in Java verwenden?

Die Verwendung von Generika macht unseren Code wartungsfreundlicher, da bei jeder Änderung der Anforderungen weniger datentypspezifischer Code geschrieben werden muss. Durch die Verwendung eines generischen begrenzten Typs können Sie den Datentyp einschränken und gleichzeitig Ihrem Code Flexibilität verleihen, indem Sie seinen Bereich definieren. Es ist weniger wahrscheinlich, dass Ihr Code zu einem späteren Zeitpunkt fehlschlägt, da er die Typensicherheit erhöht und Ihren Code weniger fehleranfällig macht.

Gültigkeitsbereich für Generika in Java

Der generische Bereich ist auf die Kompilierungszeit beschränkt. Dies bedeutet, dass das generische Konzept nur zur Kompilierungszeit, nicht jedoch zur Laufzeit anwendbar ist. Beispielsweise,

ArrayList myList = new ArrayList();

ArrayList myList = new ArrayList();

ArrayList myList = new ArrayList();

ArrayList myList = new ArrayList();

Hier sind alle obigen vier Aussagen ein und dasselbe. Sie ermöglichen das Hinzufügen beliebiger Datentypen zum Listenobjekt.

Fazit

Generics macht das Codieren für einen Codierer einfach. Dies verringert die Wahrscheinlichkeit, dass ClassCastException zur Laufzeit auftritt, indem eine strenge Typprüfung durchgeführt wird. Das Typumwandeln entfällt vollständig, sodass weniger Code geschrieben werden muss. Es bietet uns die Möglichkeit, generische Algorithmen zu entwickeln, die unabhängig von dem Datentyp sind, mit dem sie arbeiten.

Empfohlene Artikel

Dies war eine Anleitung zu Was ist Generics in Java ?. Hier diskutierten wir die Fähigkeiten, den Umfang, die Arbeitsweise, das Verständnis und den Vorteil von Generika in Java. Sie können auch unsere anderen Artikelvorschläge durchgehen, um mehr zu erfahren -

  1. Was ist das Common Gateway Interface?
  2. So installieren Sie Java 8
  3. Was ist soapUI?
  4. Was ist JavaScript?
  5. Java Booleans