Menu
Coddy logo textTech

Einführung in Generics

Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy — Lektion 53 von 87.

Stellen Sie sich vor, Sie müssen eine Klasse erstellen, die einen Wert speichert und ihn später wieder abruft. Ohne Generics müssten Sie für jeden Typ separate Klassen schreiben – eine für Integer, eine für String, eine für Double und so weiter. Dies führt zu Codeduplizierung und Wartungsproblemen.

Generics lösen dieses Problem, indem sie es Ihnen ermöglichen, Klassen und Methoden zu schreiben, die mit jedem Typ funktionieren, während die Typsicherheit gewahrt bleibt. Sie definieren einen Platzhalter (einen sogenannten Typparameter), der durch einen tatsächlichen Typ ersetzt wird, wenn Sie die Klasse verwenden:

// Ohne Generics - verwendet Object, erfordert Casting
List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0);  // Manuelles Casting erforderlich

// Mit Generics - typsicher, kein Casting
List<String> list = new ArrayList<String>();
list.add("Hello");
String s = list.get(0);  // Kein Casting erforderlich

Die spitzen Klammern <T> bezeichnen einen Typparameter. Wenn Sie List<String> schreiben, teilen Sie dem Compiler mit, dass diese Liste nur Strings enthalten wird. Wenn Sie versuchen, einen Integer hinzuzufügen, erkennt der Compiler den Fehler sofort, anstatt erst zur Laufzeit zu scheitern.

Generics bieten zwei wesentliche Vorteile: Sie erübrigen explizites Casting und sie erkennen Typfehler bereits zur Kompilierzeit statt erst zur Laufzeit. Dies macht Ihren Code sowohl sicherer als auch sauberer. In den folgenden Lektionen werden wir untersuchen, wie Sie Ihre eigenen generischen Klassen und Methoden erstellen.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein einfaches Speichersystem erstellen, das die Leistungsfähigkeit von Generics demonstriert, indem wir den alten Weg (Verwendung von Object mit Casting) mit dem neuen Weg (Verwendung von Generics mit Typsicherheit) vergleichen.

Sie werden drei Dateien erstellen, um den Unterschied hautnah zu erleben:

  • OldBox.java: Erstellen Sie eine Klasse, die Werte auf die Art und Weise vor der Einführung von Generics speichert. Ihre OldBox sollte ein privates Feld content vom Typ Object haben. Fügen Sie einen Konstruktor hinzu, der ein Object akzeptiert und speichert, sowie eine getContent()-Methode, die das Object zurückgibt. Dieser Ansatz funktioniert, erfordert aber ein Casting beim Abrufen von Werten.
  • GenericBox.java: Erstellen Sie nun die moderne, typsichere Version unter Verwendung von Generics. Ihre GenericBox sollte einen Typparameter T in ihrer Deklaration verwenden. Sie benötigt ein privates Feld content vom Typ T, einen Konstruktor, der einen T-Wert akzeptiert, und eine getContent()-Methode, die den Typ T zurückgibt. Bei der Verwendung dieser Klasse ist kein Casting erforderlich!
  • Main.java: Demonstrieren Sie beide Ansätze nebeneinander. Sie erhalten zwei Eingaben: ein Wort (String) und eine Nummer (Integer).

    Verwenden Sie zuerst den alten Ansatz: Erstellen Sie eine OldBox, die das Wort speichert, rufen Sie es dann mit einem Cast zu String ab und geben Sie aus: OldBox (with cast): [value]

    Verwenden Sie als Nächstes den generischen Ansatz: Erstellen Sie eine GenericBox<String>, die dasselbe Wort speichert, rufen Sie es ohne Casting ab und geben Sie aus: GenericBox (no cast): [value]

    Zeigen Sie dann, wie Generics mit Integern funktionieren: Erstellen Sie eine GenericBox<Integer>, die die Nummer speichert, rufen Sie sie ab und geben Sie aus: GenericBox Integer: [value]

    Geben Sie schließlich eine Leerzeile aus, gefolgt von: Type safety: Generics catch errors at compile time!

Sie erhalten zwei Eingaben nacheinander: ein Wort (String) und eine Nummer (Integer als String, den Sie parsen müssen).

Beachten Sie den entscheidenden Unterschied: Bei OldBox müssen Sie (String) box.getContent() casten und hoffen, dass Sie den richtigen Typ erwischt haben. Bei GenericBox kennt der Compiler den Typ und es ist kein Casting erforderlich. Dies ist der Hauptvorteil von Generics – Typsicherheit ohne den Aufwand des Castings!

Spickzettel

Generics ermöglichen es Ihnen, Klassen und Methoden zu schreiben, die mit jedem Typ funktionieren, während die Typsicherheit gewahrt bleibt. Sie verwenden Typparameter (Platzhalter), die durch tatsächliche Typen ersetzt werden, wenn die Klasse verwendet wird.

Ohne Generics (unter Verwendung von Object):

List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0);  // Manual casting required

Mit Generics (typsicher):

List<String> list = new ArrayList<String>();
list.add("Hello");
String s = list.get(0);  // No casting needed

Erstellen einer generischen Klasse:

public class GenericBox<T> {
    private T content;
    
    public GenericBox(T content) {
        this.content = content;
    }
    
    public T getContent() {
        return content;
    }
}

Verwenden einer generischen Klasse:

GenericBox<String> stringBox = new GenericBox<String>("Hello");
String value = stringBox.getContent();  // No casting

GenericBox<Integer> intBox = new GenericBox<Integer>(42);
Integer number = intBox.getContent();  // Type-safe

Die spitzen Klammern <T> bezeichnen einen Typparameter. Zu den Vorteilen gehören: kein explizites Casting erforderlich und Typfehler werden zur Kompilierzeit statt zur Laufzeit abgefangen.

Probier es selbst

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String word = scanner.nextLine();
        int number = Integer.parseInt(scanner.nextLine());
        
        // TODO: Erstelle eine OldBox, die word speichert
        // Mit Cast zu String abrufen und ausgeben: "OldBox (with cast): [value]"
        
        // TODO: Erstelle eine GenericBox<String>, die word speichert
        // Ohne Casting abrufen und ausgeben: "GenericBox (no cast): [value]"
        
        // TODO: Erstelle eine GenericBox<Integer>, die number speichert
        // Abrufen und ausgeben: "GenericBox Integer: [value]"
        
        // TODO: Eine Leerzeile ausgeben, dann ausgeben:
        // "Type safety: Generics catch errors at compile time!"
    }
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung