跳过编译器,获取泛型参数的实际类型
import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Vector; public class GenericTest { public static void main(String[] args) throws Exception { //泛型类型是给编译器看的,编译成class字节码文件后会丢弃类型信息,所以通过反射是无法知道泛型所存储的实际类型的 List<String> list = new ArrayList<String>(); list.add("java"); //collection.add(20); //编译报错,因为编译期间严格检查泛型的实际数据类型 //由上结论可知,既然编译成class文件后不会保存类型信息,那么是不是就可以通过反射的方式存储任意类型的数据呢? //示例:通过反射在collection中存储除String以外的数据 list.getClass().getMethod("add", Object.class).invoke(list,5); list.getClass().getMethod("add", Object.class).invoke(list, new Date()); System.out.println(list.size()); //结果是3 //用下面的方式去获取元素会报ClassCaseException,因为List中第1和第2条记录都不是String类型,所以取出来的时候会报类型转换异常 //System.out.println(list.get(1)); //说明:上面示例只想说明,JAVA中的泛型是提供给编译器检查使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会丢弃“类型”信息,使用程序运行效率不受影响 //由于无法在运行期间获取某个带类型的集合属性的实际类型,但可以获得方法参数列表中泛型参数的实际类型 Method method = GenericTest.class.getMethod("getGenericActualType", List.class,Vector.class); Type[] types = method.getGenericParameterTypes(); for(int i = 0; i < types.length; i++) { ParameterizedType pt = (ParameterizedType) types[i]; System.out.print("泛型原始类型: " + pt.getRawType() + "\t"); System.out.println("泛型实际类型: " + pt.getActualTypeArguments()[0]); } } /* * 获得泛型参数的原始类型,示例方法 */ public static void getGenericActualType(List<Date> list,Vector<String> vector) { } }
通过反编译工具获取GenericTest.class的源代码: