Java学习之反射机制及应用场景介绍
前言:
最近公司正在进行业务组件化进程,其中的路由实现用到了Java的反射机制,既然用到了就想着好好学习总结一下,其实无论是之前的EventBus2.x版本还是Retrofit、早期的View注解框架都或多或少的用到Java的反射机制。
什么是Java反射机制?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的以及动态调用对象的方法的功能称为Java的反射机制。
反射机制提供了哪些功能?
- 在运行时判定任意一个对象所属的类
- 在运行时构造任意一个类的对象;
- 在运行时判定任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的方法;
- 生成动态代理;
Java反射机制类:
java.lang.Class;//类 java.lang.reflect.Constructor;//构造方法 java.lang.reflect.Field;//类的成员变量 java.lang.reflect.Method;//类的方法 java.lang.reflect.Modifier;//访问权限
Java反射机制实现:
1.)class对象的获取
//第一种方式通过对象getClass方法 Personperson=newPerson(); Class<?>class1=person.getClass(); //第二种方式通过类的class属性 class1=Person.class; try{ //第三种方式通过Class类的静态方法——forName()来实现 class1=Class.forName("com.whoislcj.reflectdemo.Person"); }catch(ClassNotFoundExceptione){ e.printStackTrace(); }
2.)获取class对象的摘要信息
booleanisPrimitive=class1.isPrimitive();//判断是否是基础类型 booleanisArray=class1.isArray();//判断是否是集合类 booleanisAnnotation=class1.isAnnotation();//判断是否是注解类 booleanisInterface=class1.isInterface();//判断是否是接口类 booleanisEnum=class1.isEnum();//判断是否是枚举类 booleanisAnonymousClass=class1.isAnonymousClass();//判断是否是匿名内部类 booleanisAnnotationPresent=class1.isAnnotationPresent(Deprecated.class);//判断是否被某个注解类修饰 StringclassName=class1.getName();//获取class名字包含包名路径 PackageaPackage=class1.getPackage();//获取class的包信息 StringsimpleName=class1.getSimpleName();//获取class类名 intmodifiers=class1.getModifiers();//获取class访问权限 Class<?>[]declaredClasses=class1.getDeclaredClasses();//内部类 Class<?>declaringClass=class1.getDeclaringClass();//外部类
3.)获取class对象的属性、方法、构造函数等
Field[]allFields=class1.getDeclaredFields();//获取class对象的所有属性 Field[]publicFields=class1.getFields();//获取class对象的public属性 try{ FieldageField=class1.getDeclaredField("age");//获取class指定属性 FielddesField=class1.getField("des");//获取class指定的public属性 }catch(NoSuchFieldExceptione){ e.printStackTrace(); } Method[]methods=class1.getDeclaredMethods();//获取class对象的所有声明方法 Method[]allMethods=class1.getMethods();//获取class对象的所有方法包括父类的方法 ClassparentClass=class1.getSuperclass();//获取class对象的父类 Class<?>[]interfaceClasses=class1.getInterfaces();//获取class对象的所有接口 Constructor<?>[]allConstructors=class1.getDeclaredConstructors();//获取class对象的所有声明构造函数 Constructor<?>[]publicConstructors=class1.getConstructors();//获取class对象public构造函数 try{ Constructor<?>constructor=class1.getDeclaredConstructor(newClass[]{String.class});//获取指定声明构造函数 ConstructorpublicConstructor=class1.getConstructor(newClass[]{});//获取指定声明的public构造函数 }catch(NoSuchMethodExceptione){ e.printStackTrace(); } Annotation[]annotations=class1.getAnnotations();//获取class对象的所有注解 Annotationannotation=class1.getAnnotation(Deprecated.class);//获取class对象指定注解 TypegenericSuperclass=class1.getGenericSuperclass();//获取class对象的直接超类的Type Type[]interfaceTypes=class1.getGenericInterfaces();//获取class对象的所有接口的type集合
4.)class对象动态生成
//第一种方式Class对象调用newInstance()方法生成 Objectobj=class1.newInstance(); //第二种方式对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成 Constructor<?>constructor=class1.getDeclaredConstructor(newClass[]{String.class});//获取指定声明构造函数 obj=constructor.newInstance(newObject[]{"lcj"});
5.)动态调用函数
try{ //生成新的对象:用newInstance()方法 Objectobj=class1.newInstance(); //判断该对象是否是Person的子类 booleanisInstanceOf=objinstanceofPerson; //首先需要获得与该方法对应的Method对象 Methodmethod=class1.getDeclaredMethod("setAge",newClass[]{int.class}); //调用指定的函数并传递参数 method.invoke(obj,28); method=class1.getDeclaredMethod("getAge"); Objectresult=method.invoke(obj,newClass[]{}); }catch(InstantiationExceptione){ e.printStackTrace(); }catch(IllegalAccessExceptione){ e.printStackTrace(); }catch(NoSuchMethodExceptione){ e.printStackTrace(); }catch(InvocationTargetExceptione){ e.printStackTrace(); }
6.)通过反射机制获取泛型类型
例如下面这种结构
//People类 publicclassPeople<T>{} //Person类继承People类 publicclassPerson<T>extendsPeople<String>implementsPersonInterface<Integer>{} //PersonInterface接口 publicinterfacePersonInterface<T>{}
获取泛型类型
Person<String>person=newPerson<>(); //第一种方式通过对象getClass方法 Class<?>class1=person.getClass(); TypegenericSuperclass=class1.getGenericSuperclass();//获取class对象的直接超类的Type Type[]interfaceTypes=class1.getGenericInterfaces();//获取class对象的所有接口的Type集合 getComponentType(genericSuperclass); getComponentType(interfaceTypes[0]);
getComponentType具体实现
privateClass<?>getComponentType(Typetype){ Class<?>componentType=null; if(typeinstanceofParameterizedType){ //getActualTypeArguments()返回表示此类型实际类型参数的Type对象的数组。 Type[]actualTypeArguments=((ParameterizedType)type).getActualTypeArguments(); if(actualTypeArguments!=null&&actualTypeArguments.length>0){ componentType=(Class<?>)actualTypeArguments[0]; } }elseif(typeinstanceofGenericArrayType){ //表示一种元素类型是参数化类型或者类型变量的数组类型 componentType=(Class<?>)((GenericArrayType)type).getGenericComponentType(); }else{ componentType=(Class<?>)type; } returncomponentType; }
6.)通过反射机制获取注解信息
这里重点以获取Method的注解信息为例
try{ //首先需要获得与该方法对应的Method对象 Methodmethod=class1.getDeclaredMethod("jumpToGoodsDetail",newClass[]{String.class,String.class}); Annotation[]annotations1=method.getAnnotations();//获取所有的方法注解信息 Annotationannotation1=method.getAnnotation(RouterUri.class);//获取指定的注解信息 TypeVariable[]typeVariables1=method.getTypeParameters(); Annotation[][]parameterAnnotationsArray=method.getParameterAnnotations();//拿到所有参数注解信息 Class<?>[]parameterTypes=method.getParameterTypes();//获取所有参数class类型 Type[]genericParameterTypes=method.getGenericParameterTypes();//获取所有参数的type类型 Class<?>returnType=method.getReturnType();//获取方法的返回类型 intmodifiers=method.getModifiers();//获取方法的访问权限 }catch(NoSuchMethodExceptione){ e.printStackTrace(); }
反射机制的应用场景:
- 逆向代码,例如反编译
- 与注解相结合的框架例如Retrofit
- 单纯的反射机制应用框架例如EventBus2.x
- 动态生成类框架例如Gson
反射机制的优缺点:
优点:运行期类型的判断,动态类加载,动态代理使用反射。
缺点: 性能是一个问题,反射相当于一系列解释操作,通知jvm要做的事情,性能比直接的java代码要慢很多。
总结:
Java的反射机制在平时的业务开发过程中很少使用到,但是在一些基础框架的搭建上应用非常广泛,今天简单的总结学习了一下,还有很多未知的知识等以后用到再做补充。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。