Historie der Frage:
Generics wurden in Java 5 eingeführt, um eine sichere Arbeit mit Typen von Sammlungen und Methoden zu gewährleisten. Sie wurden jedoch mit Unterstützung der Rückwärtskompatibilität zu zuvor geschriebenem Bytecode realisiert. Zu diesem Zweck wurde der Mechanismus der Typlöschung (Type Erasure) angewendet.
Problem:
Der Java-Compiler erfordert eine strenge Typisierung, jedoch weiß die JVM zur Laufzeit nichts über die Typisierungsparameter, und viele alte Klassen und Bibliotheken, einschließlich der Java-Sammlungsbibliothek selbst, arbeiten mit allgemeinen „roh“-Typen (raw types). Ohne Rückwärtskompatibilität wäre es unmöglich gewesen, bestehende Entwicklungen zu unterstützen.
Lösung:
Type Erasure ist der Prozess der Umwandlung von parametrierte Typen (Generics) in ihre „rohen“ Versionen, sodass die JVM mit bereits bestehendem Bytecode arbeiten kann, ohne Änderungen. Alle Informationen über Typparameter werden während der Kompilierung entfernt, stattdessen werden Objekte des Typs Object verwendet (oder eine Einschränkung, wenn über extends angegeben).
Beispielcode:
List<String> stringList = new ArrayList<>(); stringList.add("hello"); String s = stringList.get(0); // get gibt Object zurück, der Compiler fügt einen Cast ein
Schlüsselfunktionen:
List<String>, List<Integer> usw. handelte.Kann man Methoden nur anhand der Generics-Parameter überladen?
Nein. Aufgrund der Typlöschung betrachtet der Compiler Methoden mit denselben Namen und unterschiedlichen Generics-Parametern als identisch, da die Parameter gelöscht werden. Zum Beispiel:
// Kompilierungsfehler! void process(List<String> list) { } void process(List<Integer> list) { }
Kann man ein Array eines generischen Typs erstellen?
Nein, nicht direkt. Type Erasure erlaubt es der JVM nicht, ein Array eines bestimmten generischen Typs zu speichern, zum Beispiel:
List<String>[] array = new List<String>[10]; // Kompilierungsfehler
Man kann dies umgehen, indem man ein Array von rohen Typen verwendet, aber das ist unsicher:
List<String>[] array = (List<String>[]) new List[10];
Kann man den Typ eines Generics zur Laufzeit über instanceof überprüfen?
Nein, da die Informationen über die Parameter gelöscht werden. Überprüfung:
if (obj instanceof List<String>) { ... } // Kompilierungsfehler
Richtiger wäre es, nur den Basistyp zu überprüfen:
if (obj instanceof List) { ... }
Ein Programmierer erstellt ein Array parametrisierter Typen zur Speicherung von Listen verschiedener Parameter. Letztlich tritt nach längerer Laufzeit des Programms eine ClassCastException auf, wenn ein Objekt aus dem Array abgerufen wird — die Typisierung zur Laufzeit wird nicht sichergestellt.
Vorteile:
Nachteile:
Statt Arrays werden Sammlungen verwendet (z. B. List<List<String>>), und alle Typüberprüfungen werden dem Compiler überlassen.
Vorteile:
Nachteile: