In einer solchen Funktion:
%Vor% Der Typ von obj.getClass()
ist Class<?>
und nicht Class<? extends T>
. Warum?
Der folgende Code funktioniert einwandfrei:
%Vor% Also scheint die Signatur von T#getClass()
ein Class<? extends T>
zurückzugeben, oder?
Warum ist die Signatur anders, wenn T
wirklich eine generische ist?
Um das Problem zu überwinden (und um klarer zu machen, um was ich herumwandere), habe ich diese Funktion implementiert:
%Vor% Nochmal die Frage: Warum ist die Besetzung hier und nicht im String
Fall? Und warum ist das?
SuppressWarnings
benötigt? Ist es nicht immer klar aus dem Code, dass es immer in der Lage ist, diesen Cast sicher durchzuführen?
Gibt es eine Möglichkeit, ein Class<? extends T>
von obj
zu bekommen? Wenn ja, wie? Wenn nicht, warum nicht?
Eine Möglichkeit wäre, classOf
zu verwenden. Das wäre sicher, oder? Wenn das immer sicher ist und einen sicheren Weg gibt, wirklich eine Class<? extends T>
(statt einer Class<?>
) zu bekommen, warum gibt es dann in Java keine solche Funktion? Oder ist es?
Wie wäre es mit diesem Fall:
%Vor% array.getClass().getComponentType()
gibt erneut Class<?>
und nicht Class<? extends T>
zurück. Warum?
Ich habe diese Funktion implementiert:
%Vor%Ist das wieder sicher zu verwenden?
Um mehr zu klären, worüber ich mich wundere. Betrachten Sie diesen Demo-Code:
%Vor% Das funktioniert gut. Aber das gleiche gilt nicht für Object#getClass()
.
Warum war es beispielsweise nicht möglich, eine generische Schnittstelle wie ClassInstance<T>
mit der Funktion getClass()
zu haben und jedes Java-Objekt dies automatisch zu implementieren? Dies würde genau jene Verbesserungen haben, über die ich spreche, über die Lösung, sie von einer nicht-generischen Basisklasse Object
zu erweitern.
Oder Object
als generische Klasse haben:
Denken Sie nun an myClass()
als getClass()
und denken Sie daran, dass der Compiler das automatisch zu jeder Klasse hinzufügt. Es hätte viele dieser Casting-Probleme gelöst.
Die Hauptfrage, über die ich spreche ist: Warum wurde es nicht so gemacht?
Oder um es noch einmal mit anderen Worten zu sagen: Hier beschreibe ich mehr Detailliere die Lösung einer solchen classOf
-Funktion, die das Problem überwindet. Warum wurde es nicht so gemacht, dh warum ist die ursprüngliche Funktion nicht so?
(Ich möchte nicht wirklich eine Antwort bekommen wie: Die Art und Weise, wie Java gerade funktioniert, dh die Erweiterung von einem nicht-generischen Object
, das diese Funktion definiert, macht das nicht möglich. Ich frage, warum es nicht war. t irgendwie anders gelöst, so dass es möglich gewesen wäre.)
Das grundlegende Problem ist, dass getClass () die Klasse nicht zurückgibt, weil sie auf der Object-Ebene definiert ist. d. h. es ist im wesentlichen als eine Klasse definiert, die das Objekt erweitert. Sie könnten getClass () wie definiert haben.
%Vor%aber stattdessen sein
%Vor%was bedeutet, dass Generika nicht verstehen, was getClass zurückgibt.
In Java sind Generika nur ein Quellenniveauwerkzeug für sicherere Entwicklung.
Die JVM weiß nichts über Generika. Der Java-Compiler verwirft diese Informationen und alle generischen Typen sind zur Laufzeit nur Objektreferenzen. Um dies zu kompensieren, fügt der Compiler die notwendigen Umwandlungen ein. Dieses Verfahren nennt sich Type Erasure (Google!).
%Vor%wird zur Laufzeit
%Vor% Um Ihr Problem zu lösen, könnten Sie versuchen, die einzelnen Elemente in Ihrem Array ( arr[0].getClass()
) zu untersuchen.
Es gibt ein paar nicht ganz genaue Antworten hier. Generics werden zwar mit Type-Erasure implementiert, dies bedeutet jedoch nicht, dass alle Typinformationen verloren gehen. Der Compiler löscht den Typ auf die niedrigste erlaubte Grenze.
So & lt; T erweitert String & gt; wird in String gelöscht; Deshalb gibt getClass für einen String die Klasse & lt; erweitert String & gt ;. Ihre unbegrenzte & lt; T & gt; wird jedoch im Objekt gelöscht; und so gibt getClass die Klasse & lt; dehnt das Objekt & gt; aus, d. h. Klasse & lt; & gt;
Generika sind komplex und sie tun nicht immer, was Sie wollen, aber es gibt Möglichkeiten, um viele Dinge zu umgehen (indem Sie Ihre Grenzen verbessern, auf Informationen zum Laufzeittyp über Reflektion zugreifen und Klassenobjekte herumreichen). Typ-Löschung ist eigentlich eine ziemlich clevere Lösung, die viel von der schlechten Presse nicht verdient hat.
Wegen Typlöschung behält die Laufzeittypinformation für generische Arrays nicht bei. In der Tat behandelt die JVM alle generischen Arrays intern so, als ob sie ein Objekt [] sind.
Wenn Sie einen Laufzeittyp erhalten möchten, besteht Ihre beste Option möglicherweise einfach darin, getClass () für das erste Element im Array aufzurufen. Sie müssen natürlich einen Weg finden, den leeren Fall zu behandeln, und den Fall, in dem die enthaltenen Objekte mehrere Typen haben, usw.