Java-Generics schreiben Löschen: Wann und was passiert?
Lese ich über Java type erasure auf der Oracle-website.
Wenn nicht Typ erasure auftreten? Bei der Kompilierung oder zur Laufzeit? Wenn die Klasse geladen wird? Wenn die Klasse instanziiert wird?
Viele Websites (einschließlich der offiziellen tutorial oben erwähnt) sagen, geben Sie die Löschung erfolgt zur compile-Zeit. Wenn die Typ-Informationen vollständig entfernt wird zur compile-Zeit, wie funktioniert das JDK Typ Kontrollkästchen Kompatibilität beim eine Methode die Verwendung von Generika ist aufgerufen, mit Nein geben Sie Informationen oder falsche Informationen eingeben?
Betrachten Sie das folgende Beispiel: Sagen Klasse A
hat eine Methode empty(Box<? extends Number> b)
. Wir kompilieren A.java
und Holen Sie sich die class-Datei A.class
.
public class A {
public static void empty(Box<? extends Number> b) {}
}
public class Box<T> {}
Nun erstellen wir eine weitere Klasse B
die ruft die Methode empty
mit einer nicht-parametrisierten argument (raw-Typ): empty(new Box())
. Wenn wir kompilieren B.java
mit A.class
im classpath javac ist smart genug, um zu erheben eine Warnung. So A.class
hat irgendeine Art Informationen in ihm gespeichert sind.
public class B {
public static void invoke() {
//java: unchecked method invocation:
// method empty in class A is applied to given types
// required: Box<? extends java.lang.Number>
// found: Box
//java: unchecked conversion
// required: Box<? extends java.lang.Number>
// found: Box
A.empty(new Box());
}
}
Meine Vermutung wäre, dass der Typ Löschung tritt auf, wenn die Klasse geladen wird, aber es ist nur eine Vermutung. Also, Wann soll es passieren?
InformationsquelleAutor der Frage | 2008-12-04
Du musst angemeldet sein, um einen Kommentar abzugeben.
Type erasure gilt für die verwenden von Generika. Es ist definitiv Metadaten in der Klassendatei zu sagen, ob oder nicht Sie eine Methode/Art ist generic, und was die Einschränkungen sind, etc. Aber wenn die Generika sind verwendetSie sind umgewandelt in die compile-Zeit überprüft und Ausführung-Zeit wirft. Also dieser code:
ist zusammengestellt in
Zeitpunkt der Ausführung gibt es keine Möglichkeit herauszufinden, dass
T=String
für das list-Objekt - information ist verschwunden.... aber die
List<T>
Schnittstelle selbst noch wirbt sich als generic.EDIT: Nur zur Klarstellung, der compiler übernimmt, behalten die Informationen über die variable ein
List<String>
- aber Sie kann immer noch nicht herausfinden, dassT=String
für das list-Objekt selbst.InformationsquelleAutor der Antwort Jon Skeet
Den compiler ist verantwortlich für das Verständnis der Generika zur compile-Zeit. Der compiler ist auch verantwortlich für das wegwerfen dieses "verstehen" von generischen Klassen, die in einem Prozess nennen wir type erasure. All das geschieht bei der Kompilierung.
Hinweis: Entgegen der überzeugungen der Mehrheit der Java-Entwickler, ist es möglich, compile-time type Informationen und das abrufen dieser Informationen zur Laufzeit, obwohl Sie in einer sehr eingeschränkten Weise. In anderen Worten: Java bietet vergegenständlicht Generika in einer sehr eingeschränkten Weise.
Über type erasure
Beachten Sie, dass zur compile-Zeit, hat der compiler die vollständige Typ-Informationen verfügbar, aber diese Informationen absichtlich gelöscht im Allgemeinenwenn der byte-code erzeugt, in einem Prozeß bekannt als type erasure. Dies ist auf diese Weise getan, da es Kompatibilitätsprobleme: Die Absicht, die Sprache der Designer war es, die full-source-code-Kompatibilität und full-byte-code-Kompatibilität zwischen Versionen der Plattform. Wenn es anders implementiert, müsste man neu kompilieren Ihre legacy-Anwendungen, die bei der Migration auf neuere Versionen der Plattform. Die Art und Weise war es geschafft, alle Signaturen sind erhalten (source code Kompatibilität) und Sie brauchen nicht zu kompilieren, alles andere (Binär-Kompatibilität).
Über vergegenständlicht generics in Java
Wenn Sie brauchen, um compile-time type information, die Sie benötigen, zu beschäftigen, anonyme Klassen.
Der Punkt ist: in dem sehr speziellen Fall von anonymen Klassen ist es möglich, zum abrufen von full compile-Zeit-Typ-Informationen zur Laufzeit, die in anderen Worten bedeutet: verdinglicht Generika. Dies bedeutet, dass der compiler nicht wegwerfen, geben Sie Informationen, wenn anonyme Klassen beteiligt sind; diese Informationen werden in den erzeugten Binär-code und runtime-system ermöglicht das abrufen dieser Informationen.
Habe ich einen Artikel geschrieben über dieses Thema:
http://rgomes-info.blogspot.co.uk/2013/12/using-typetokens-to-retrieve-generic.html
Einen Hinweis über die Technik, beschrieben in dem Artikel oben steht, dass die Technik ist obscure für die Mehrheit der Entwickler. Trotz, es funktioniert und funktioniert gut, die meisten Entwickler sich verwirrt fühlen oder unwohl mit der Technik. Wenn Sie eine gemeinsame code-Basis oder veröffentlichen Sie Ihren code an die öffentlichkeit, die ich nicht empfehlen, das obige Verfahren. Auf der anderen Seite, wenn Sie der alleinige Benutzer Ihres Codes, können Sie die Vorteile der macht, die diese Technik bietet.
Beispielcode
Dem Artikel oben hat links zu Beispiel-code.
InformationsquelleAutor der Antwort Richard Gomes
Wenn Sie ein Feld haben, dass ist ein generischer Typ, dem Typ-Parameter sind zusammengestellt in der Klasse.
Wenn Sie eine Methode oder gibt einen generischen Typ, den Typ-Parameter sind zusammengestellt in der Klasse.
Diese information ist das, was der compiler verwendet, um zu sagen, dass Sie nicht passieren können einen
Box<String>
zu denempty(Box<T extends Number>)
Methode.Die API ist kompliziert, aber Sie können überprüfen, diese Art von Informationen durch die reflection-API mit Methoden wie
getGenericParameterTypes
getGenericReturnType
und für Felder,getGenericType
.Wenn Sie code haben, verwendet einen generischen Typ, fügt der compiler CASTET als nötig (der Anrufer) , check-Typen. Die generischen Objekte selbst sind nur der raw type; der parametrisierte Typ ist "gelöscht". Also, wenn Sie erstellen eine
new Box<Integer>()
gibt es keine Informationen über dieInteger
Klasse in derBox
Objekt.Angelika Langer ' s FAQ ist die beste Referenz, die ich gesehen habe für Java Generics.
InformationsquelleAutor der Antwort erickson
Generics in Java Sprache ist eine wirklich gute Anleitung zu diesem Thema.
So, es ist zur compile-Zeit. Die JVM wird nie wissen, welche
ArrayList
Sie verwendet.Ich würde auch empfehlen Mr. Skeet Antwort auf Was ist das Konzept der Löschung in generics in Java?
InformationsquelleAutor der Antwort Eugene Yokota
Typ Auslöschung geschieht bei der Kompilierung. Welche Art der Löschung bedeutet, dass es vergessen wird über den generischen Typ hat, nicht über jede Art. Außerdem gibt es noch Metadaten über Typen als generische. Zum Beispiel
umgewandelt
zur compile-Zeit. Sie erhalten möglicherweise Warnungen nicht, weil der compiler weiß, welche Art ist die generische, sondern im Gegenteil, weil Sie nicht wissen, genug, so dass es keine Garantie geben Sicherheit.
Zusätzlich der compiler ist beibehalten Art Informationen über die Parameter in einer Methode aufrufen, die Sie abrufen über Reflexion.
Diese guide ist die beste, die ich gefunden habe zu dem Thema.
InformationsquelleAutor der Antwort Vinko Vrsalovic
Ich habe festgestellt mit type erasure in Android. In der Produktion verwenden wir gradle mit verkleinern option. Nach der Verkleinerung habe ich schwere Ausnahmefehler. Ich habe einfache Funktion, um zu zeigen, Vererbungskette des Objekts:
Und es gibt zwei Ergebnisse dieser Funktion:
Nicht minified code:
Minified code:
So, in den minified code tatsächliche parametrisierten Klassen ersetzt werden, die mit raw-Klassen-Typen ohne jede Art von Informationen.
Als Lösung für mein Projekt habe ich alle entfernt Reflexion fordert und replced Sie mit expliziten params-Typen übergeben Sie in der Funktion Argumente.
InformationsquelleAutor der Antwort porfirion