學習java的同學注意了!??! 學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Java學習交流群,群號碼:523047986 我們一起學Java!
今天遇到一個小問題,讓我感覺Java的泛型(因為背負了歷史的包袱導致的)有點雞肋啊。
我們經常會遇到要一些自定義的key-value字符串,比如:
"key1:1k;key2:2;key3:3"通常編碼的時候會將它轉換為一個Map這樣方便操作,因為key和value的類型不一定(可能是int也可能是String等),于是我用Java寫了一個簡單的泛型方法:
@SupPRessWarnings("unchecked") public static <K, V> Map<K, V> getMap(String source, String firstSplit, String secondSplit) { Map<K, V> result = new HashMap<K, V>(); if (source.equals("")) { return result; } String[] strings = source.split(firstSplit); for (int i = 0; i < strings.length; i++) { String[] tmp = strings[i].split(secondSplit); if (tmp.length == 2) { result.put((K) tmp[0], (V) tmp[1]); // System.out.println("(K) tmp[0]:"+((K) tmp[0]).getClass()); // System.out.println("(V) tmp[1]:"+((V) tmp[1]).getClass()); } } return result; }看上去貌似可以正常工作的,用上面的字符串舉例子,我應該希望得到的是Map<String, Integer>這樣一個結果。
String test = "key1:1k;key2:2;key:3"; Map<String, Integer> map = getMap(test, ";", ":"); for (Entry<String, Integer> entry : map.entrySet()) { Integer value = entry.getValue(); }上面的代碼編譯時完全沒問題的,但是一運行:
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integerat ossp.demo.generic.GenericDemo.main(GenericDemo.java:38)
報的是類型轉換錯誤,String不能轉換為Interger類型?但是明明entry.getValue()結果就是Interger類型啊,難道不是嗎?
一開始很疑惑,但稍微一想就明白了,哦!Java泛型用的是“擦除”法,完全是編譯期的,運行時已經沒有泛型參數的類型信息了,也就是說運行時所有的泛型參數都被替換成了Object(如果有泛型約束(.net是這么叫的)是不是就替換成上限類型?)所以上面的泛型方法其實就等價于:
public static Map<Object, Object> getMap(String source, String firstSplit, String secondSplit) { Map<Object, Object> result = new HashMap<Object, Object>(); if (source.equals("")) { return result; } String[] strings = source.split(firstSplit); for (int i = 0; i < strings.length; i++) { String[] tmp = strings[i].split(secondSplit); if (tmp.length == 2) { result.put((Object) tmp[0], (Object) tmp[1]); } } return result; }也就是說entry.getValue();返回的其實是一個Object對象的,它的類型應該是java.lang.String,于是我想那么這樣轉換一下應該可以了:
Integer value = Integer.valueOf(entry.getValue());但是讓我郁悶的是仍然報之前的錯誤,鼠標點上去,智能提示看執行的應該是參數為int的重載反復,額,又繞回去了。
那怎么才能得到我想得到那個Integer的value呢???最后我發現這樣是可以的:
Integer value = Integer.valueOf(String.valueOf(entry.getValue()));我靠!這太讓我無語了。不光如此我發現直接執行下面這行代碼也會報類型轉換錯誤:
System.out.println(entry.getValue().getClass());既然entry.getValue()的類型是java.lang.String,為什么Map<String, Integer> map = getMap2(test, ";", ":");和Entry<Object, Integer> entry : map.entrySet()這兩行又都能編譯通過呢?想想還是萬惡的“類型擦除“的原因,我們先看看C#里的情況。
Dictionary<string, int> dic1 = new Dictionary<string, int>(); Dictionary<string, double> dic2 = new Dictionary<string, double>(); Console.WriteLine(dic1); Console.WriteLine(dic2);我們知道.NET泛型將每個類型參數理解為一個獨立的類型,所以上面dic1和dic2的類型是不一樣的:
但是在Java里因為“類型擦除“實際上Map<String,Interger>和Map<String,Double>的類型都是:java.util.HashMap
Map<String, Integer> map1 = new HashMap<String, Integer>();Map<String, Double> map2 = new HashMap<String, Double>();System.out.println(map1.getClass());System.out.println(map2.getClass());
這樣看來上面的代碼編譯通過是必須的,那么這智能提示有什么意義呢(編譯期的YY?)。
我們看看同樣的問題C#是怎么解決的。一開始我以為像Java那樣直接強制類型轉換就可以:
或者這樣:
這些都是不行的。但是只要運行運行時還有類型參數的信息,那么肯定是有辦法辦到的,.NET中庫中就有現成的這樣一個方法:Convert.ChangeType,于是我們可以寫出下面這個輔助泛型方法:
static V GenericCast<U, V>(U obj) { return (V)Convert.ChangeType(obj, typeof(V)); }于是乎為了解決我的問題,我可以寫這樣一個泛型方法了:
static Dictionary<K, V> ToMap<K, V>(string source, string firstSplit, string secondSpilt) { Dictionary<K, V> result = new Dictionary<K, V>(); if (String.IsNullOrEmpty(source)) { return result; } string[] info1 = source.Split(new string[] { firstSplit }, StringSplitOptions.RemoveEmptyEntries); foreach (var item in info1) { string[] info2 = item.Split(new string[] { secondSpilt }, StringSplitOptions.RemoveEmptyEntries); if (info2.Length == 2) { result.Add(GenericCast<string, K>(info2[0]), GenericCast<string, V>(info2[1])); } } return result; }string test = "key1:1.1;key2:2;key3:3"; Dictionary<string, double> map = ToMap<string, double>(test, ";", ":"); foreach (var item in map) { Console.WriteLine(item.Key + ":" + item.Value); }
并不是想黑Java,只是之前用C#的泛型用的比較爽,用Java的總感覺有點食之無味,棄之可惜。
學習Java的同學注意了?。?! 學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Java學習交流群,群號碼:523047986 我們一起學Java!
新聞熱點
疑難解答