Ich bin neu in Java Generics, und ich habe Probleme, herauszufinden, seine inneren Abläufe. Wenn Erasures vom Compiler durchgeführt wird, entfernen Sie alle Typparameter, die es in einer .java-Datei gibt, und erzeugen Sie eine normale .class-Datei, die von älteren JVMs verstanden wird. Wie können wir dann eine solche Klasse generisch referenzieren? von anderen Klassen, wissend, dass es die .class-Datei ist, mit der der Java-Compiler arbeitet, wenn wir andere Klassen aus unserem Programm referenzieren? Wie behandelt der Compiler alle Object Referenzen in dieser .class-Datei in Bezug auf die Entscheidung, die ursprünglich Objekt ist und die das Ergebnis von Erasure ist?Generics, Erasures und Bytecode
Antwort
Kurz gesagt, Details über Generika und ihre Einschränkungen in Typdeklarationen, Methodensignaturen usw. werden immer noch als Metadaten im Bytecode codiert.
Der Compiler verwendet diese Informationen zur Kompilierzeit, aber die JVM verwendet sie zur Laufzeit nicht. Diese Information ist durch Reflektion zugänglich, und einige Bibliotheken benutzen sie (Hibernate macht das).
Siehe mehr detailed answer here
Edit: ein kleines Experiment in der Praxis spielen zu sehen. In Ergänzung zu @Andy Turners Antwort (die sehr informativ ist: Es zeigt, dass die generische Art Info dort ist), mal sehen, was zur Laufzeit passiert.
Wir prüfen die Klassenstruktur durch Reflexion, und bauen eine Foo<Integer>
mit einem String
anstelle des Integer
:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
class Foo<T> {
T field;
void bar(List<T> list) {
T obj = list.get(0);
T zip = field;
}
public static void main(String[] args) throws ReflectiveOperationException {
Field field = Foo.class.getDeclaredField("field");
System.out.println("Field:"
+ "\n - " + field.getType()
+ "\n - " + field.getGenericType()
+ "\n - " + field.getAnnotatedType()
);
Method method = Foo.class.getDeclaredMethod("bar", List.class);
System.out.println("Method:"
+ "\n - " + Arrays.toString(method.getParameterTypes())
+ "\n - " + Arrays.toString(method.getGenericParameterTypes())
);
Foo<Integer> foo = new Foo<>();
// foo.field = "hi"; <- Compile error, incompatible types
field.set(foo, "hi"); //
// Integer value = foo.field; <- Accepted by compiler, fails at runtime with ClassCastException
Object value = foo.field; // OK
System.out.println("Value of field: " + value + " (class: " + value.getClass() + ")");
}
}
Ergebnis:
Field:
- class java.lang.Object
- T
- sun.re[email protected]5a2e4553
Method:
- [interface java.util.List]
- [java.util.List<T>]
Value of field: hi (class: class java.lang.String)
Die Generika in Klassen- und Methodensignaturen und Elementvariablen werden nicht gelöscht.
Eine einfache Klasse:
class Foo<T> {
T field;
void bar(List<T> list) {
T obj = list.get(0);
T zip = field;
}
}
dekompilierten:
class Foo<T> { // Still got the <T> here.
T field; // Still got the T here.
Foo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
void bar(java.util.List<T>); // Still got the <T> here.
Code:
0: aload_1
1: iconst_0
// But T has been erased inside the method body.
2: invokeinterface #2, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
7: astore_2
8: aload_0
// And T has been erased when referencing field.
9: getfield #3 // Field field:Ljava/lang/Object;
12: astore_3
13: return
}
erzeugen eine normale .class-Datei, die von älteren JVMs
Diese isn verstanden werden kann Ist das der Fall: wenn yo Wenn Sie Code kompilieren, der Generics verwendet, kann er von JVMs, die keine Generika unterstützen, nicht verstanden werden.
Klassendateien, die auf früheren Versionen kompiliert wurden, sind mit späteren JVMs kompatibel, aber nicht umgekehrt.
- 1. Java Generics Typ Erasure Bytecode
- 2. Bytecode-Analyse in Java
- 3. javap und generics type löschen
- 4. Java Generics, erweitert Generics und abstrakte Klassen
- 5. Exploring und decompiling Python-Bytecode
- 6. Hibernate-Validierung und Bytecode-Erweiterung
- 7. Bytecode-Manipulationsmuster
- 8. Java: Instanceof und Generics
- 9. Java Generics und Zahlen
- 10. C# Generics und Winform
- 11. C# Generics und Typüberprüfung
- 12. EclipseLink @MappedSuperclass und Generics
- 13. Delphi: OleVariant und Generics
- 14. Java Generics und Komparator
- 15. Generics, Interfaces und Activator
- 16. Generics und Listen
- 17. Generics und Classcast
- 18. Java Generics und Reflexion!
- 19. Vererbung und Generics
- 20. C# Generics und Sammlungen
- 21. GWT und Generics
- 22. Abgeleitete Typen und Generics
- 23. Generics und Rx
- 24. Java Generics und JNI
- 25. Generics, Überladungsauflösung und Delegierten
- 26. Implizite Operatorumwandlung und Generics
- 27. Java Generics und Vererbung
- 28. C# Casting und Generics
- 29. Generics und instanceof - Java
- 30. Schnittstellen und Generics
Dank. Aber das ist neu für mich: Ich dachte, der resultierende Bytecode wäre derselbe, und Erasures half nur dabei, das zu erhalten. Es ist eine Quellcode Sache - Compiler-Gebiet .., nicht ganz sicher, obwohl ... – Searcherer