昨天朋友圈問了一個問題:
對於下面的list,何如在list添加一個Integer型整數?java
ArrayList<String> list = new ArrayList<String>();複製代碼
有這樣幾種回答:bash
對於一、2就不說了,屬於搞事情的!三、四、5三種方式違背了問題的初衷,若是能夠改,那咱們直接new三個ArrayList就能夠了。6反射,這個是無限接近的,那麼這個和反射有什麼關係呢?下來看下下面幾個例子:spa
public static void main(String[] args) {
ArrayList list=new ArrayList();
ArrayList<String> str_list=new ArrayList<String>();
ArrayList<Integer> int_list=new ArrayList<Integer>();
ArrayList<Object> obj_list=new ArrayList<Object>();
//對象比較
System.out.println(list == str_list);
System.out.println(list == int_list);
System.out.println(list == obj_list);
//對象的運行時class比較
System.out.println(list.getClass() == str_list.getClass());
System.out.println(list.getClass() == int_list.getClass());
System.out.println(list.getClass() == obj_list.getClass());
}複製代碼
結果:code
false
false
false
true
true
true複製代碼
其實上面三個很容易理解,不一樣對象在內存中的地址確定是不一樣的,所以均爲false;下面三個均爲true?是的,確實爲true,這就引出了朋友圈的那個問題。爲何不一樣的三個對象,他們的getClass是同樣的,不該該是有三個不一樣的hashCode嗎?這個其實就是泛型編譯時和運行時的問題。
對於泛型來講,泛型只在編譯階段有效,編譯以後,集合的泛型是去泛型化的;緣由:因爲JVM泛型的擦除機制,在運行時JVM是不知道泛型信息的。
所以:java集合中的泛型,是來約束用戶的錯誤輸入的,只在編譯時有效;
在回到問題最初,咱們怎麼才能將一個Integer對像放入上面定義的list中呢?既然集合中的泛型是編譯時有效的,那我咱們就能夠經過繞過編譯的方式進行插入。那麼如何繞過編譯時的校驗呢?答案就是用反射;咱們知道JAVA反射機制是指:
「在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱爲java語言的反射機制。
OK,再來看程序:對象
ArrayList<String> str_list=new ArrayList<String>();
//獲取類信息
Class c=str_list.getClass();
//獲取add方法
Method m=c.getMethod("add", Object.class);
//運行時調用add方法
m.invoke(str_list, 20);
//輸出當前str_list
System.out.println(str_list);複製代碼
結果:內存
[20]複製代碼
從結果能夠看出,咱們完成了在list中添加Integer的任務。
【泛型、反射、編譯時、運行時】
你們週末愉快!get