Java之reflection(反射机制)——经过反射操做泛型,注解

1、反射操做泛型(Generic)


  Java采用泛型擦除机制来引入泛型。Java中的泛型仅仅是给编译器Javac使用的,确保数据的安全性和免去强制类型转换的麻烦。可是编译一旦完成,全部和泛型有关的类型所有被擦除。 
  为了经过反射操做这些类型以迎合实际开发的须要,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来表明不能被归一到Class类中的类型可是又和原始类型齐名的类型。 
  java

  • ParameterizedType:表示一种参数化的类型,好比Collection< String >
  • GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
  • TypeVariable:是各类类型变量的公共父接口
  • 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性能

2、反射操做注解(Annotation)

Method/Constructor/Field/Element 都继承了 AccessibleObject , AccessibleObject 类中有一个 setAccessible 方法:测试


具体使用能够就看个人以前的文章 注解处理器spa

好了,介绍了两个简单的反射的应用,在顺便讲一下Java反射机制的性能问题。.net

3、反射性能测试

Method/Constructor/Field/Element 都继承了 AccessibleObject , AccessibleObject 类中有一个 setAccessible 方法:code

public void setAccessible(booleanflag)throws SecurityException { ... }

该方法有两个做用:对象

  1. 启用/禁用访问安全检查开关:值为true,则指示反射的对象在使用时取消Java语言访问检查; 值为false,则指示应该实施Java语言的访问检查;
  2. 能够禁止安全检查, 提升反射的运行效率.

测试代码

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+次(并且服务器的性能也确定比个人机器要高),所以在咱们的实际开发中,实际上是不用担忧反射机制带来的性能消耗的,并且禁用访问权限检查,也会有性能的提高。

相关文章
相关标签/搜索