我今天被愛學習的同學問到了如何在List<String>里面放一個int的數據
比如
List<String> list = new ArrayList<String>();
int a = 1;
list.add(a);
這樣寫肯定報錯了。毫無疑問。
先不管為什么他要給我來一個不合理的問題。先管實現。
這里我首先考慮到一個事情,泛型是什么,不加泛型的話
List list = new ArrayList();
int a = 1;
String str = "1"
list.add(a);
list.add(str);
是不會報錯的。
那么泛型這個到底做了啥?
深究是不可能的,這輩子都不想去深究。
但是綜合經驗來看。
這是一個語法糖。
所謂語法糖,只是方便程序員寫的,減少異常出現可能性等的一個手段,實際上編譯器最后會把語法糖廢掉,并用基礎的方式去搞
如果把編譯好的自己碼.class文件拿去反編譯,你會發現
List<String> list = new ArrayList<String>();
String a= "1"
list.add(a);
編譯,并反編譯,下面是反編譯的結果
List list = new ArrayList();
String a = "1";
list.add(a);
是的,<String>被廢了,當我添加一個數據獲取操作的時候,計算長度
list.get(0).length();
編譯,并反編譯,下面是反編譯的結果
((String)list.get(0)).length();
嗯,原來如此,看到了吧。編譯器給我們來了一個(String)的類型轉換。
那么
List list = new ArrayList();
String a= "1";
list.add(a);
((String) list.get(0)).length();
這段代碼的編譯結果和上面那段的一樣,也就是少了<String>泛型約束,多了(String)類型轉換。稍加思考,你會懂得的。
所以如何在List<String>里放int呢?
通過上面的分析,我們可以得出某種結論:用了泛型,經過編譯器后,會出現”類型擦除“的現象,并添加強制類型轉換的操作。
那么,如果我自己做類型擦出呢?
這里有個故事,昨天晚上我想到用反射,嗯,成功了,于是我今天來寫文章,但是剛剛寫著寫著,我,發現,類型擦除,并不需要反射,看代碼
1 List<String> list = new ArrayList<String>();
2 list.add("str");
3 List list2 = list;
4 list2.add(1);
5 System.out.println(list);
6 System.out.println((int)((Object)list.get(1))+1);
第一行我聲明一個泛型List<String> list
第二行給list添加一個字符串,目的是做參照
第三行生么一個無泛型的 List list2 ,并讓他=list,注意,這里是地址引用,也就是list2和list指向同一個對象地址空間!(細節百度,不長篇大論)
第四行給list2放一個int類型的數字
然后打印list,發現,塞進去了?
并且做數學運算成功了?
看下字節碼反編譯:
List list = new ArrayList();
list.add("str");
List list2 = list;
list2.add(Integer.valueOf(1));
System.out.println(list);
System.out.println(((Integer)list.get(1)).intValue() + 1);
他做了啥呀,list的類型擦除,lsit2添加int,list.get(1)的一系列操作。
再解釋就不對了,我本來只想說怎么放的,幾行代碼的事情,一時興起就搞一下編譯器相關,順便優化了昨天反射的方法,還不錯,所謂的溫故而知新。古人誠不欺我!
理解這個需要
java語法(寫了這么多年)
懂得jvm內存原理(我一知半解)
編譯器原理(我猜的)
我的程序員守則(我先管實現,再管你和不合理,傻逼要在List<String>里面放int,這違背了java語言泛型的設計初衷,不過他說這是某教學視頻的課后習題)