问题描述
import java.lang.reflect.InvocationTargetException;import java.util.ArrayList;import java.util.Date;public class BaiduDemo05 { public static void main(String[] args) throws NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { ArrayList<Integer> collection1 = new ArrayList<Integer>(); collection1.getClass().getMethod("add", Object.class).invoke(collection1, "abc"); System.out.println(collection1.get(0));//ABC ArrayList<String> collection2 = new ArrayList<String>(); collection2.getClass().getMethod("add", Object.class).invoke(collection2, "abc"); System.out.println(collection2.get(0));//ABC ArrayList collection22 = new ArrayList(); collection22.getClass().getMethod("add", Object.class).invoke(collection22, "abc"); System.out.println(collection22.get(0));//ABC ArrayList<Long> collection3 = new ArrayList<Long>(); collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abc"); System.out.println(collection3.get(0));//ABC ArrayList<Date> collection4 = new ArrayList<Date>(); collection4.getClass().getMethod("add", Object.class).invoke(collection4, 1); System.out.println(collection4.get(0));//ABC }}但是在将abc替换为1时,只有第2个,也就是collection2会出现异常,求解释,谢谢大师。 问题补充:chen_yongkai 写道
解决方案
至于“类型擦除”: ArrayList<String> collection2 = new ArrayList<String>(); collection2.getClass().getMethod("add", Object.class).invoke(collection2, 1); System.out.println(collection2.get(0));//ABC 编译后相当于: ArrayList collection2 = new ArrayList(); //这里是擦除了 collection2.getClass().getMethod("add", Object.class).invoke(collection2, 1); System.out.println((String)collection2.get(0));//因为 PrintStream有对应的println(String s)的方法,所以会有强制类型转化。
解决方案二:
引用那为什么下面的Date,将abc换成1后也不报错呢因为Date调用的是public void println(Object x) ,是以Object类型来打印的,不需要类型转换。
解决方案三:
ArrayList<Date> collection4 = new ArrayList<Date>(); collection4.getClass().getMethod("add", Object.class).invoke(collection4, 1); 这个直接打印就不做泛型检查了?这个是不报错的。就String的通不过,费解!!! 这个打印调用的是println(Object x)方法,Date是Object的子类能通过检查。
解决方案四:
很明显,无解。。
解决方案五:
或者这样也行:ArrayList<String> collection2 = new ArrayList<String>();collection2.getClass().getMethod("add", Object.class).invoke(collection2, 1);Object object = collection2.get(0);System.out.println(object);//ABC 总之就是想办法跳过println(String x)的泛型检查就行了。
解决方案六:
System.out.println(collection2.get(0))需要对泛型进行检查,但反射不检查泛型,你add方法是通过反射用的,get方法也应该可以通过反射用:ArrayList<String> collection2 = new ArrayList<String>();collection2.getClass().getMethod("add", Object.class).invoke(collection2, 1);//System.out.println(collection2.get(0));//ABC Object obj1 = collection2.getClass().getMethod("get", int.class).invoke(collection2, 0);System.out.println(obj1);
解决方案七:
问题出在System.out.println方法上,查看PrintStream类,发现它的println方法有如下几种: public void println(String x) {synchronized (this) { print(x); newLine();} } public void println(Object x) {synchronized (this) { print(x); newLine();} }。。。其他的就不列举了。ArrayList<String> collection2 = new ArrayList<String>(); collection2 声明的泛型是String,所以调用collection2.get(0)时,编译器认为它返回的是String 类型对象,所以println方法应该是调用第一种,如果你往collection2 中add是整数1,取回来的就是Integer对象,那么就会发生类型转换错误。至于为什么能用反射方法往collection2 中加入1,我想你应该知道的,不然不会写出这样的例子,挺有意思的。
解决方案八:
反射出来的是不带泛型的,所以可以把字符串放进List<Integer>,同理,取出来也都是Object类型,打印的话,自动调用toString,所以看到abc
解决方案九:
ArrayList<String> collection2 = new ArrayList<String>();这个泛型是String啊!collection2.getClass().getMethod("add", Object.class).invoke(collection2, 1); 肯定错了,你应该把ArrayList<String> collection2 = new ArrayList<String>();改为ArrayList<Integer> collection2 = new ArrayList<Integer>()
解决方案十:
ArrayList<String> collection2 = new ArrayList<String>();这个泛型是String啊!collection2.getClass().getMethod("add", Object.class).invoke(collection2, 1); 肯定错了,你应该把ArrayList<Integer> collection2 = new ArrayList<String>();