答案似乎超越@Telthien和@newacct的答案。我很好奇, 「看」 爲自己的區別是:用明確地打字
System.out.println(Util.<String>compare("a", "b"));
,並:
System.out.println(Util.compare(new String(""), new Long(1)));
與隱式類型。
我進行了幾個實驗,使用前兩行的變化。這些實驗表明,即使在使用anonymous/local class trick時,編譯器在編譯期間也會檢查類型,但生成的字節碼僅指代Object
,即使在第一行的情況下。
下面的代碼段示出了類型轉換甚至可以在顯式類型參數<String>
的情況下安全地進行一路Object
。
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);
}
}
的main
方法的字節碼的樣子:
// 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[]
它實際上是有道理的,所有的調用總是與Object
作爲正式的參數類型的方法,如解釋in another question/answer。總而言之,編譯器總是使用Object
來生成字節碼,無論是明示類型參數(第一行)還是隱式類型參數都無關緊要,但對象可以具有不同於Object
的公共超類。
這裏要注意這一點,即使你鏈接到它;這種現象被稱爲「類型刪除」。 – 2014-11-07 01:50:20
是的。基本上,Java將泛型實現爲幕後的類型轉換。例如,'ArrayList'在內部將每個元素都視爲Object,但在使用時會自動將其轉換回String。 –
2016-02-04 19:50:28