Im Gegensatz zu .NET Java werden Generika durch eine Technik namens "Type Erasure" implementiert.
Das bedeutet, dass der Compiler beim Generieren der Klassendateien die Typinformationen verwendet, diese Informationen jedoch nicht in den Bytecode überträgt. Wenn Sie sich die kompilierten Klassen mit javap oder ähnlichen Werkzeugen ansehen, werden Sie feststellen, dass ein List<String>
ein einfacher List
(von Object
) in der Klassendatei ist, genauso wie es in Pre-Java-5-Code war.
Code, der auf die generische Liste zugreift, wird vom Compiler "neu geschrieben", um die Umwandlungen einzuschließen, die Sie selbst in früheren Versionen schreiben müssten. In der Tat sind die beiden folgenden Codefragmente aus einer Bytecode Perspektive identisch einmal die Compiler mit ihnen durchgeführt wird:
Java 5:
List<String> stringList = new ArrayList<String>();
stringList.add("Hello World");
String hw = stringList.get(0);
Java 1.4 und vor:
List stringList = new ArrayList();
stringList.add("Hello World");
String hw = (String)stringList.get(0);
Beim Lesen Werte aus einer generischen Klasse in Java 5 wird die notwendige Umwandlung in den deklarierten Typparameter automatisch eingefügt. Beim Einfügen prüft der Compiler den Wert, den Sie eingeben möchten, und bricht mit einem Fehler ab, wenn es sich nicht um einen String handelt.
Die ganze Sache wurde getan, um alte Bibliotheken und neuen generierten Code interoperabel zu halten, ohne die vorhandenen Bibliotheken neu kompilieren zu müssen. Dies ist ein großer Vorteil gegenüber der .NET-Methode, bei der generische Klassen und nicht-generische Klassen nebeneinander existieren, aber nicht beliebig untereinander ausgetauscht werden können.
Beide Ansätze haben ihre Vor- und Nachteile, aber so ist es in Java.
Um zu Ihrer ursprünglichen Frage zurückzukehren: Sie werden zur Laufzeit nicht in der Lage sein, an die Typinformationen zu kommen, weil sie einfach nicht mehr da sind, sobald der Compiler seine Arbeit getan hat. Dies ist sicherlich in gewisser Weise einschränkend und es gibt einige verschrobene Möglichkeiten, die normalerweise darauf basieren, irgendwo eine Klasseninstanz zu speichern, aber dies ist kein Standardmerkmal.
Der Wunsch, dies zu tun, ist fast ein schlechtes Design Wahl sein garantiert. Es ist gut möglich, dass die if-Anweisung Kenntnisse über jeden "Typ" erfordert, damit sie implementiert werden können. Daher sollten Sie wahrscheinlich alle diese Klassen vom selben übergeordneten Typ haben, und "do this" sollte eine virtuelle Methode sein. Es kann beinhalten, Klassen zu umhüllen, aber insgesamt verbessert sich Ihr Design, wenn Sie diesen Weg gehen. –
Die Möglichkeiten in den if-Anweisungen sind Kantenfälle unter allen möglichen Aufruftypen, die insgesamt völlig getrennte Implementierungen erfordern. Ich bin damit einverstanden, was Sie hier sagen, aber die spezifische Anwendung ist ein Stein und ein harter Ort. –
Die Notwendigkeit, die Klasse für einen generischen Typparameter abzurufen, ist nicht immer eine schlechte Entwurfsentscheidung. Eine legitime Anforderung (meins!) Könnte ein Methodenaufruf sein, der einen Parameter der Klasse <> erfordert. – dahvyd