2 回答

TA貢獻(xiàn)1809條經(jīng)驗(yàn) 獲得超8個(gè)贊
T運(yùn)行時(shí)不存在。它解析為約束的下限。在本例中,沒(méi)有,因此解析為Object。一切都可以轉(zhuǎn)換為Object,因此沒(méi)有類轉(zhuǎn)換異常。
如果您要將約束更改為此
private static <V,T extends Map<?,?>> T castToType(V value, T type){
return (T) value;
}
然后轉(zhuǎn)換為T轉(zhuǎn)換為下界Map,這顯然Integer不是,并且您會(huì)得到您期望的類轉(zhuǎn)換異常。
另外,當(dāng)我將同一個(gè)語(yǔ)句分成兩部分時(shí),就像
Object o = castToType(10,new HashMap<Integer,Integer>());
System.out.println(o.getClass());
它沒(méi)有拋出任何錯(cuò)誤
castToType(10,new HashMap<Integer,Integer>()).getClass()
這會(huì)引發(fā)類轉(zhuǎn)換異常,因?yàn)樗o態(tài)鏈接到方法HashMap::getClass(not Object::getClass),因?yàn)楹灻硎酒谕鸋ashMap作為返回值。這需要隱式轉(zhuǎn)換,HashMap但會(huì)失敗,因?yàn)樵谶\(yùn)行時(shí)castToType返回 an Integer。
當(dāng)你第一次使用這個(gè)時(shí)
Object o = castToType(10,new HashMap<Integer,Integer>());
您現(xiàn)在靜態(tài)鏈接,Object::getClass無(wú)論實(shí)際返回什么,都可以。
“未分割”版本相當(dāng)于這個(gè)
final HashMap<Integer, Integer> map = castToType(10, new HashMap<>());
System.out.println(map.getClass());
希望能證明差異

TA貢獻(xiàn)1111條經(jīng)驗(yàn) 獲得超0個(gè)贊
您可以使用 javap 工具看到差異。
編譯過(guò)程默認(rèn)進(jìn)行代碼優(yōu)化,將泛型類型更改為原始類型
第一個(gè)代碼:
public class ObjectUtility {
public static void main(String[] args) {
System.out.println(castToType(10,new java.util.HashMap<Integer,Integer>()));
}
private static <V,T> T castToType(V value, T type){
return (T) value;
}
}
真正的偽代碼:
Compiled from "ObjectUtility.java"
public class ObjectUtility {
public ObjectUtility();
descriptor: ()V
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: bipush 10
5: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
8: new #4 // class java/util/HashMap
11: dup
12: invokespecial #5 // Method java/util/HashMap."<init>":()V
15: invokestatic #6 // Method castToType:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
18: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
21: return
LineNumberTable:
line 4: 0
line 5: 21
private static <V, T> T castToType(V, T);
descriptor: (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
Code:
0: aload_0
1: areturn
LineNumberTable:
line 8: 0
}
通用類型的調(diào)用更改為對(duì)象,并在系統(tǒng)輸出中添加 Integer.valueOf。
第二個(gè)代碼:
public class ObjectUtility {
public static void main(String[] args) {
System.out.println(castToType(10,new java.util.HashMap<Integer,Integer>()).getClass());
}
private static <V,T> T castToType(V value, T type){
return (T) value;
}
}
真正的偽代碼:
Compiled from "ObjectUtility.java"
public class ObjectUtility {
public ObjectUtility();
descriptor: ()V
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: bipush 10
5: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
8: new #4 // class java/util/HashMap
11: dup
12: invokespecial #5 // Method java/util/HashMap."<init>":()V
15: invokestatic #6 // Method castToType:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
18: checkcast #4 // class java/util/HashMap
21: invokevirtual #7 // Method java/lang/Object.getClass:()Ljava/lang/Class;
24: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
27: return
LineNumberTable:
line 4: 0
line 5: 27
private static <V, T> T castToType(V, T);
descriptor: (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
Code:
0: aload_0
1: areturn
LineNumberTable:
line 8: 0
}
checkcast 通過(guò) HashMap 調(diào)用,但簽名更改為 Object,返回值是 int,沒(méi)有在castToType 中進(jìn)行強(qiáng)制轉(zhuǎn)換?!癷nt”基元類型導(dǎo)致無(wú)效的強(qiáng)制轉(zhuǎn)換
第三個(gè)代碼:
public class ObjectUtility {
public static void main(String[] args) {
Object o = castToType(10,new java.util.HashMap<Integer,Integer>());
System.out.println(o.getClass());
}
private static <V,T> T castToType(V value, T type){
return (T) value;
}
}
真正的偽代碼:
Compiled from "ObjectUtility.java"
public class ObjectUtility {
public ObjectUtility();
descriptor: ()V
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
Code:
0: bipush 10
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: new #3 // class java/util/HashMap
8: dup
9: invokespecial #4 // Method java/util/HashMap."<init>":()V
12: invokestatic #5 // Method castToType:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
15: astore_1
16: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #7 // Method java/lang/Object.getClass:()Ljava/lang/Class;
23: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
26: return
LineNumberTable:
line 4: 0
line 5: 16
line 6: 26
private static <V, T> T castToType(V, T);
descriptor: (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
Code:
0: aload_0
1: areturn
LineNumberTable:
line 9: 0
}
在這種情況下,方法與第一種類似。castToType 返回第一個(gè)參數(shù)而不做任何更改。
正如您所看到的,java 編譯器進(jìn)行了一些“性能”更改,這些更改在某些情況下可能會(huì)產(chǎn)生影響。泛型是源代碼的“發(fā)明”,最終會(huì)轉(zhuǎn)換為任何情況下所需的實(shí)際類型。
添加回答
舉報(bào)