Die Antwort scheint über @Teldhien und @newacct 'Antworten zu gehen. Ich war neugierig, zu "sehen" für mich den Unterschied zwischen:
System.out.println(Util.<String>compare("a", "b"));
mit explicity Typisierung, und:
System.out.println(Util.compare(new String(""), new Long(1)));
mit impliziter Typisierung.
Ich führte mehrere Experimente durch, wobei ich Variationen dieser beiden vorherigen Zeilen verwendete. Diese Experimente zeigen, dass der Compiler die Typen während der Kompilierung überprüft, aber die generierten Bytecodes beziehen sich nur auf Object
, selbst im Fall der ersten Zeile.
Der folgende Codeabschnitt zeigt, dass Typumwandlungen selbst bei dem Explicity-Typ-Argument <String>
sicher bis Object
ausgeführt werden können.
public final class Example44 {
public static void main(final String[] args) {
System.out.println(new Util44<String>().compare("a", "b"));
System.out.println(new Util44().compare(new String(""), new Long(1)));
}
}
final class Util44<T> {
private T aT;
public boolean compare(T t1, T t2) {
System.out.println(this.aT);
// I was expecting the second and third assignments to fail
// with the first invocation because T is explicitly a String
// and then to work with the second invocation because I use
// a raw type and the compiler must infer a common type for T.
// Actually, all these assignments succeed with both invocation.
this.aT = (T) new String("z");
this.aT = (T) new Long(0);
this.aT = (T) new Object();
return t1.equals(t2);
}
}
Die Bytecode des main
Methode wie folgt aussehen:
// Method descriptor #15 ([Ljava/lang/String;)V
// Stack: 7, Locals: 1
public static void main(java.lang.String[] args);
0 getstatic java.lang.System.out : java.io.PrintStream [16]
3 new ca.polymtl.ptidej.generics.java.Util44 [22]
6 dup
7 invokespecial ca.polymtl.ptidej.generics.java.Util44() [24]
10 ldc <String "a"> [25]
12 ldc <String "b"> [27]
14 invokevirtual ca.polymtl.ptidej.generics.java.Util44.compare(java.lang.Object, java.lang.Object) : boolean [29]
17 invokevirtual java.io.PrintStream.println(boolean) : void [33]
20 getstatic java.lang.System.out : java.io.PrintStream [16]
23 new ca.polymtl.ptidej.generics.java.Util44 [22]
26 dup
27 invokespecial ca.polymtl.ptidej.generics.java.Util44() [24]
30 new java.lang.String [39]
33 dup
34 ldc <String ""> [41]
36 invokespecial java.lang.String(java.lang.String) [43]
39 new java.lang.Long [46]
42 dup
43 lconst_1
44 invokespecial java.lang.Long(long) [48]
47 invokevirtual ca.polymtl.ptidej.generics.java.Util44.compare(java.lang.Object, java.lang.Object) : boolean [29]
50 invokevirtual java.io.PrintStream.println(boolean) : void [33]
53 return
Line numbers:
[pc: 0, line: 24]
[pc: 20, line: 25]
[pc: 53, line: 26]
Local variable table:
[pc: 0, pc: 54] local: args index: 0 type: java.lang.String[]
Es macht wirklich Sinn, dass alle Anrufe mit Object
als formale Parameter-Typen immer auf Methoden, wie in another question/answer erläutert. Um dies zu verdeutlichen, verwendet der Compiler immer Object
für die generierten Bytecodes, egal ob es ein Argument vom Typ explility (erste Zeile) oder ein Argument impliziten Typs gibt, aber die Objekte könnten eine gemeinsame Superklasse haben, die sich von Object
unterscheidet.
Nur um das hier zu notieren, obwohl du es verlinkt hast; Das Phänomen wird als "Typ-Löschung" bezeichnet. –
Ja. Grundsätzlich implementiert Java Generics als hinter den Kulissen Typcasting. Zum Beispiel betrachtet eine 'ArrayList' intern jedes Element als 'Objekt', es wird jedoch automatisch wieder in' String' umgewandelt, wenn Sie es verwenden. –