Menu
Coddy logo textTech

Einführung in Generics

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

Stell dir vor, du musst eine Klasse erstellen, die einen Wert speichert und ihn später abruft. Ohne Generics müsstest du separate Klassen für jeden Typ schreiben: eine für Integer, eine für String, eine für Double und so weiter. Das führt zu doppeltem Code und erheblichen Wartungsproblemen.

Generics lösen dieses Problem, indem sie dir ermöglichen, Klassen und Methoden zu schreiben, die mit jedem Typ funktionieren und dabei dennoch die Typsicherheit gewährleisten. Du definierst einen Platzhalter (genannt Typparameter), der durch einen tatsächlichen Typ ersetzt wird, wenn du die Klasse verwendest:

// 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 Typ-Parameter. Wenn du List<String> schreibst, teilst du dem Compiler mit, dass diese Liste nur Zeichenketten enthalten wird. Wenn du versuchst, eine Ganzzahl zu add, fängt der Compiler den Fehler sofort ab, anstatt erst zur Laufzeit fehlzuschlagen.

Generics bieten zwei entscheidende Vorteile: Sie machen explizite Typumwandlungen überflüssig und erkennen Typfehler zur Kompilierzeit statt zur Laufzeit. Dadurch wird dein Code sowohl sicherer als auch übersichtlicher. In den folgenden Lektionen werden wir untersuchen, wie du deine eigenen generischen Klassen und Methoden erstellst.

challenge icon

Aufgabe

Einfach

Lass uns ein einfaches Speichersystem erstellen, das die Leistungsfähigkeit von Generics demonstriert, indem es die alte Vorgehensweise (mit Object und Casting) mit der neuen Vorgehensweise (mit Generics und Typsicherheit) vergleicht.

Du wirst drei Dateien erstellen, um den Unterschied direkt zu sehen:

  • OldBox.java: Erstelle eine Klasse, die Werte auf die Art vor Generics speichert. Deine OldBox sollte ein privates Feld content vom Typ Object besitzen. Füge einen Konstruktor hinzu, der ein Object akzeptiert und speichert, sowie eine getContent()-Methode, die das Object zurückgibt. Dieser Ansatz funktioniert, erfordert aber beim Abrufen der Werte ein Casting.
  • GenericBox.java: Erstelle nun die moderne, typsichere Version mit Generics. Deine GenericBox sollte in ihrer Deklaration den Typparameter T verwenden. Sie benötigt ein privates Feld content vom Typ T, einen Konstruktor, der einen Wert vom Typ T akzeptiert, sowie eine getContent()-Methode, die den Typ T zurückgibt. Bei der Verwendung dieser Klasse ist kein Casting erforderlich!
  • Main.java: Zeige beide Ansätze nebeneinander. Du erhältst zwei Eingaben: ein Wort (String) und eine Zahl (Ganzzahl).

    Verwende zuerst den alten Ansatz: Erstelle eine OldBox, in der das Wort gespeichert wird, rufe es mit einem Cast zu String ab und gib Folgendes aus: OldBox (with cast): [value]

    Verwende als Nächstes den generischen Ansatz: Erstelle eine GenericBox<String>, in der dasselbe Wort gespeichert wird, rufe es ohne Casting ab und gib Folgendes aus: GenericBox (no cast): [value]

    Zeige anschließend, dass Generics mit Ganzzahlen funktionieren: Erstelle eine GenericBox<Integer>, in der die Zahl gespeichert wird, rufe sie ab und gib Folgendes aus: GenericBox Integer: [value]

    Gib schließlich eine leere Zeile aus, gefolgt von: Type safety: Generics catch errors at compile time!

Du erhältst zwei Eingaben in dieser Reihenfolge: ein Wort (String) und eine Zahl (Ganzzahl als String, die du parsen wirst).

Beachte den entscheidenden Unterschied: Bei OldBox musst du (String) box.getContent() casten und hoffen, dass der Typ stimmt. Bei GenericBox kennt der Compiler den Typ, und es ist kein Casting erforderlich. Das ist der zentrale Vorteil von Generics: Typsicherheit ohne den Aufwand des Castings!

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 das Wort speichert
        // Retrieve with cast to String and print: "OldBox (with cast): [value]"
        
        // TODO: Erstelle eine GenericBox<String>, die das Wort speichert
        // Retrieve without casting and print: "GenericBox (no cast): [value]"
        
        // TODO: Create a GenericBox<Integer> storing the number
        // Retrieve and print: "GenericBox Integer: [value]"
        
        // TODO: Gib eine leere Zeile aus, dann gib aus:
        // "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

Übe selbstständig: Online-Java-Compiler