之前沒做java的時候就一直聽說java的泛型是假泛型,但是一直沒有去了解過,最近做了java發現很多和C#泛型不同的地方,比如:
T t = new T(); //這段代碼在C#中是很正常的一段代碼,但是在我寫java的時候發現報錯了
what fuck?為什么這個會報錯?那我想return new T呢?
后來在網上找到了答案:Java的泛型在編譯的時候會使用“類型擦除”來實現泛型,也就是說編譯后的T會變成Object:
public class Class1<K,V> { private Dictionary<K, V> keyValuePairs = new Dictionary<K, V>(); public V Get(K k) { return keyValuePairs.GetValueOrDefault(k); } public void Set(K k,V v) { keyValuePairs.Add(k, v); } }
這段代碼,java編譯后的字節碼和C#編譯后的IL可以看出來這個問題的答案:
可以看到,IL是的TKey是在運行時確切的包含了TKey TValue的信息的,CLR會根據運行時的不同狀態生成不同的類型。而Java是直接將泛型轉換成了Object。這就很操蛋了,那這段代碼在Java中怎么實現呢:
public class Cache<TKey, TValue> { public static TValue Instance; } public class Factory { public static string Create<TKey>() { if (Cache<TKey, string>.Instance == null) { Cache<TKey, string>.Instance = // some expensive computation } return Cache<TKey, string>.Instance; } }
TKey在運行時類型就已經被擦除了,假設這里的字典/hashmap是一個<int,object>類型的,這段代碼在JVM平台上創建的應該是一個hashmap對象,並且不會區分<int,object><int,string>,因為對於jvm來說hashmap<int,object>,hashmap<int,string>都是hashmap,並沒有什么區別。