Java采用泛型擦除机制来引入泛型。Java中的泛型仅仅是给编译器Javac使用的,确保数据的安全性和免去强制类型转换的麻烦。可是编译一旦完成,全部和泛型有关的类型所有被擦除。
为了经过反射操做这些类型以迎合实际开发的须要,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来表明不能被归一到Class类中的类型可是又和原始类型齐名的类型。
java
WildcardType:表明一种通配符类型表达式,好比?、? extends Number、? super Integer。(wildcard是一个单词:就是”通配符“)数组
代码示例:安全
package reflection; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; /** * 经过反射获取泛型信息 * */ public class Demo{ //定义两个带泛型的方法 public void test01(Map<String,Person> map,List<Person> list){ System.out.println("Demo.test01()"); } public Map<Integer,Person> test02(){ System.out.println("Demo.test02()"); return null; } public static void main(String[] args) { try { //得到指定方法参数泛型信息 Method m = Demo.class.getMethod("test01", Map.class,List.class); Type[] t = m.getGenericParameterTypes(); for (Type paramType : t) { System.out.println("#"+paramType); if(paramType instanceof ParameterizedType){ //获取泛型中的具体信息 Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments(); for (Type genericType : genericTypes) { System.out.println("泛型类型:"+genericType); } } } //得到指定方法返回值泛型信息 Method m2 = Demo.class.getMethod("test02", null); Type returnType = m2.getGenericReturnType(); if(returnType instanceof ParameterizedType){ Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments(); for (Type genericType : genericTypes) { System.out.println("返回值,泛型类型:"+genericType); } } } catch (Exception e) { e.printStackTrace(); } } }
输出结果:
#java.util.Map< java.lang.String, reflection.Person >
泛型类型:class java.lang.String
泛型类型:class reflection.Person
#java.util.List< reflection.Person >
泛型类型:class reflection.Person服务器
返回值,泛型类型:class java.lang.Integer
返回值,泛型类型:class reflection.Person性能
Method/Constructor/Field/Element 都继承了 AccessibleObject , AccessibleObject 类中有一个 setAccessible 方法:测试
具体使用能够就看个人以前的文章 注解处理器spa
好了,介绍了两个简单的反射的应用,在顺便讲一下Java反射机制的性能问题。.net
Method/Constructor/Field/Element 都继承了 AccessibleObject , AccessibleObject 类中有一个 setAccessible 方法:code
public void setAccessible(booleanflag)throws SecurityException { ... }
该方法有两个做用:对象
测试代码:
package reflection; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TestReflect { public static void testNoneReflect() { Person user = new Person(); long start = System.currentTimeMillis(); for (long i = 0; i < Integer.MAX_VALUE; ++i) { user.getName(); } long count = System.currentTimeMillis() - start; System.out.println("没有反射, 共消耗 <" + count + "> 毫秒"); } public static void testNotAccess() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { Person user = new Person(); Method method = Class.forName("reflection.Person").getMethod("getName"); long start = System.currentTimeMillis(); for (long i = 0; i < Integer.MAX_VALUE; ++i) { method.invoke(user, null); } long count = System.currentTimeMillis() - start; System.out.println("没有访问权限, 共消耗 <" + count + "> 毫秒"); } public static void testUseAccess() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { Person user = new Person(); Method method = Class.forName("reflection.Person").getMethod("getName"); method.setAccessible(true); long start = System.currentTimeMillis(); for (long i = 0; i < Integer.MAX_VALUE; ++i) { method.invoke(user, null); } long count = System.currentTimeMillis() - start; System.out.println("有访问权限, 共消耗 <" + count + "> 毫秒"); } public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { testNoneReflect(); testNotAccess(); testUseAccess(); } }
输出结果:
没有反射, 共消耗 <912> 毫秒
没有访问权限, 共消耗 <4366> 毫秒 有访问权限, 共消耗 <2843> 毫秒
能够看到使用反射会比直接调用慢2000 毫秒 ,可是前提是该方法会执行20E+次(并且服务器的性能也确定比个人机器要高),所以在咱们的实际开发中,实际上是不用担忧反射机制带来的性能消耗的,并且禁用访问权限检查,也会有性能的提高。