先看個例子吧:
一共有三個:
第一個是限定爲Integer類型:
package cn.conpany.test.reflect;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
public class RefectColl {
public static void main(String[] args) throws Exception {
//定義爲Integer類型的集合,此時只能加入Integer類型
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(0);
//加入其它類型,需要通過反射跳過編譯器,必須用Object,這裏會記錄下類型
list.getClass().getMethod("add", Object.class).invoke(list, "ssss");
System.out.println("size:" + list.size());//2
//驗證get方法返回類型,只要是返回的String類型,都需強轉
System.out.println("get(0)返回類型:" + list.get(0).getClass().getName());//java.lang.Integer--->原始類型是Integer集合
System.out.println("get(1)返回類型:" + ((Object)list.get(1)).getClass().getName());//java.lang.String
//集合原始類型爲Integer類型集合,無需強轉爲Object類,可直接獲取
System.out.println("get(0)值:" + list.get(0));//0
System.out.println("get(1)值:" + list.get(1));//ssss
}
}
第二種爲String類型:
package cn.conpany.test.reflect;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
public class RefectColl2 {
public static void main(String[] args) throws Exception {
//定義爲String類型的集合,此時只能加入String類型
ArrayList<String> list = new ArrayList<String>();
list.add("abc");
//加入其它類型,需要通過反射跳過編譯器,必須用Object,這裏會記錄下類型
list.getClass().getMethod("add", Object.class).invoke(list, new Integer(123));
list.getClass().getMethod("add", Object.class).invoke(list, 124);
list.getClass().getMethod("add", Object.class).invoke(list, new Persont("ZS",20));
//這個size方法與集合定義的類型無關
System.out.println("size:" + list.size());//4
//驗證get方法返回的類型,只要是返回的String類型,都需強轉
System.out.println("get(0)返回類型:" + list.get(0).getClass().getName());//get(0)返回類型:java.lang.String--->原始類型是String集合
System.out.println("get(1)返回類型:" + ((Object)list.get(1)).getClass().getName());//get(1)返回類型:java.lang.Integer
System.out.println("get(2)返回類型:" + ((Object)list.get(2)).getClass().getName());//get(2)返回類型:java.lang.Integer
System.out.println("get(3)返回類型:" + ((Object)list.get(3)).getClass().getName());//get(3)返回類型:cn.conpany.test.reflect.Persont
//可直接獲取編譯器前的原類型,即String類型
System.out.println("get(0)值:" + list.get(0));//abc
//集合的原始類型定義爲String集合類型,所以,需要先強轉爲Object類,才能獲取,否則編譯失敗
System.out.println("get(1)值:" + (Object)list.get(1));//123
System.out.println("get(2)值:" + (Object)list.get(2));//124
System.out.println("get(3)值:" + (Object)list.get(3));//name:ZS,age:20
}
}
第三種爲Persont類型
//定義Persont類
class Persont{
private String name;
private int age;
public Persont(String name, int age) {
this.name = name;
this.age = age;
}
public String toString(){
return "name:" + name + ",age:" + age;
}
}
package cn.conpany.test.reflect;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
public class RefectColl3 {
public static void main(String[] args) throws Exception {
//定義爲String類型的集合,此時只能加入String類型
ArrayList<Persont> list = new ArrayList<Persont>();
list.add(new Persont("LS",27));
//加入其它類型,需要通過反射跳過編譯器,必須用Object,這裏會記錄下類型
list.getClass().getMethod("add", Object.class).invoke(list, new Integer(123));
list.getClass().getMethod("add", Object.class).invoke(list, 124);
list.getClass().getMethod("add", Object.class).invoke(list, new Persont("ZS",20));
//這個size方法與集合定義的類型無關
System.out.println(list.size());//4
//驗證get方法返回的類型,只要是返回的String類型,都需強轉
System.out.println("get(0)返回類型:" + list.get(0).getClass().getName());//cn.conpany.test.reflect.Persont--->原始類型是Persont集合
System.out.println("get(1)返回類型:" + ((Object)list.get(1)).getClass().getName());//java.lang.Integer
System.out.println("get(2)返回類型:" + ((Object)list.get(2)).getClass().getName());//java.lang.Integer
System.out.println("get(3)返回類型:" + ((Object)list.get(3)).getClass().getName());//cn.conpany.test.reflect.Persont
//可直接獲取跳過編譯器前的原類型,即String類型
System.out.println("get(0)值:" + list.get(0));//name:LS,age:27
//集合的原始類型定義的是Persont集合類型,無需強轉,直接獲取
System.out.println("get(1)值:" + list.get(1));//123
System.out.println("get(2):" + list.get(2));//124
System.out.println("get(3):" + list.get(3));//name:ZS,age:20
}
}
結論:代碼很多,但是你認真看了,就會發現一個特別有趣的現象:
1、查看ArrayList的API文檔,你就可以發現,其中的ArrayList是這樣定義的:ArrayList<E>,而其中的add方法定義爲:boolean add(E e),你是不是發現了什麼,沒錯,即使反射將類型擦出了,其實反射是脆弱的,即使擦出了集合的類型信息,但是其中的方法可能還會保留原始限定的類型,所以,在加入的時候,仍需要用Object.class。
2、對於返回類型與集合無法的,如size這個方法,無需強轉,直接獲取。
3、很重要的一點:除了String類型以外的其他類型(包括自定義類型),無需強轉,可以直接使用相應集合中的方法。如上面的get()方法。我個人理解,與集合有關的方法,如get方法只有在你添加進元素時,才能調用,所以,即使get定義爲:E get(int index),也無需強轉。這裏,String類型除外。
4、但是對於String類型呢?作爲String類型的值,如果添加入限定爲非String集合中,那麼就需要強轉,究其原因,我只能說String是比較特殊的一個類,它有如下特性:被定義爲final,而且其值是存在了常量池中,並且可以將任意類型值通過字符串打印。基於如此特殊的類,那麼,它必然也有某些特性。這裏,我會繼續探究,如果誰有個人見解,請多指教,謝謝