java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言, 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台 (即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se)) 的总称
本篇文章主要介绍了 Java 反射机制及应用场景, 反射机制是很多 Java 框架的基石非常具有实用价值, 需要的朋友可以参考下
前言:
最近公司正在进行业务组件化进程, 其中的路由实现用到了 Java 的反射机制, 既然用到了就想着好好学习总结一下, 其实无论是之前的 EventBus 2.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 方法
- Person person = new Person();
- Class < ?>class1 = person.getClass();
- // 第二种方式 通过类的 class 属性
- class1 = Person.class;
- try {
- // 第三种方式 通过 Class 类的静态方法 forName()来实现
- class1 = Class.forName("com.whoislcj.reflectdemo.Person");
- } catch(ClassNotFoundException e) {
- e.printStackTrace();
- }
2.)获取 class 对象的摘要信息
- boolean isPrimitive = class1.isPrimitive(); // 判断是否是基础类型
- boolean isArray = class1.isArray(); // 判断是否是集合类
- boolean isAnnotation = class1.isAnnotation(); // 判断是否是注解类
- boolean isInterface = class1.isInterface(); // 判断是否是接口类
- boolean isEnum = class1.isEnum(); // 判断是否是枚举类
- boolean isAnonymousClass = class1.isAnonymousClass(); // 判断是否是匿名内部类
- boolean isAnnotationPresent = class1.isAnnotationPresent(Deprecated.class); // 判断是否被某个注解类修饰
- String className = class1.getName(); // 获取 class 名字 包含包名路径
- Package aPackage = class1.getPackage(); // 获取 class 的包信息
- String simpleName = class1.getSimpleName(); // 获取 class 类名
- int modifiers = 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 {
- Field ageField = class1.getDeclaredField("age");// 获取 class 指定属性
- Field desField = class1.getField("des");// 获取 class 指定的 public 属性
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- }
- Method[] methods = class1.getDeclaredMethods();// 获取 class 对象的所有声明方法
- Method[] allMethods = class1.getMethods();// 获取 class 对象的所有方法 包括父类的方法
- Class parentClass = class1.getSuperclass();// 获取 class 对象的父类
- Class<?>[] interfaceClasses = class1.getInterfaces();// 获取 class 对象的所有接口
- Constructor<?>[] allConstructors = class1.getDeclaredConstructors();// 获取 class 对象的所有声明构造函数
- Constructor<?>[] publicConstructors = class1.getConstructors();// 获取 class 对象 public 构造函数
- try {
- Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{String.class});// 获取指定声明构造函数
- Constructor publicConstructor = class1.getConstructor(new Class[]{});// 获取指定声明的 public 构造函数
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- }
- Annotation[] annotations = class1.getAnnotations();// 获取 class 对象的所有注解
- Annotation annotation = class1.getAnnotation(Deprecated.class);// 获取 class 对象指定注解
- Type genericSuperclass = class1.getGenericSuperclass();// 获取 class 对象的直接超类的 Type
- Type[] interfaceTypes = class1.getGenericInterfaces();// 获取 class 对象的所有接口的 type 集合
4.)class 对象动态生成
- // 第一种方式 Class 对象调用 newInstance()方法生成
- Object obj = class1.newInstance();
- // 第二种方式 对象获得对应的 Constructor 对象, 再通过该 Constructor 对象的 newInstance()方法生成
- Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{String.class});// 获取指定声明构造函数
- obj = constructor.newInstance(new Object[]{"lcj"});
5.)动态调用函数
- try {
- // 生成新的对象: 用 newInstance()方法
- Object obj = class1.newInstance();
- // 判断该对象是否是 Person 的子类
- boolean isInstanceOf = obj instanceof Person;
- // 首先需要获得与该方法对应的 Method 对象
- Method method = class1.getDeclaredMethod("setAge", new Class[] {
- int.class
- });
- // 调用指定的函数并传递参数
- method.invoke(obj, 28);
- method = class1.getDeclaredMethod("getAge");
- Object result = method.invoke(obj, new Class[] {});
- } catch(InstantiationException e) {
- e.printStackTrace();
- } catch(IllegalAccessException e) {
- e.printStackTrace();
- } catch(NoSuchMethodException e) {
- e.printStackTrace();
- } catch(InvocationTargetException e) {
- e.printStackTrace();
- }
6.)通过反射机制获取泛型类型
例如下面这种结构
- //People 类
- public class People < T > {}
- //Person 类继承 People 类
- public class Person < T > extends People < String > implements PersonInterface < Integer > {}
- //PersonInterface 接口
- public interface PersonInterface < T > {}
获取泛型类型
- Person < String > person = new Person < >();
- // 第一种方式 通过对象 getClass 方法
- Class < ?>class1 = person.getClass();
- Type genericSuperclass = class1.getGenericSuperclass(); // 获取 class 对象的直接超类的 Type
- Type[] interfaceTypes = class1.getGenericInterfaces(); // 获取 class 对象的所有接口的 Type 集合
- getComponentType(genericSuperclass);
- getComponentType(interfaceTypes[0]);
getComponentType 具体实现
- private Class < ?>getComponentType(Type type) {
- Class < ?>componentType = null;
- if (type instanceof ParameterizedType) {
- //getActualTypeArguments()返回表示此类型实际类型参数的 Type 对象的数组
- Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
- if (actualTypeArguments != null && actualTypeArguments.length > 0) {
- componentType = (Class < ?>) actualTypeArguments[0];
- }
- } else if (type instanceof GenericArrayType) {
- // 表示一种元素类型是参数化类型或者类型变量的数组类型
- componentType = (Class < ?>)((GenericArrayType) type).getGenericComponentType();
- } else {
- componentType = (Class < ?>) type;
- }
- return componentType;
- }
6.)通过反射机制获取注解信息
这里重点以获取 Method 的注解信息为例
- try {
- // 首先需要获得与该方法对应的 Method 对象
- Method method = class1.getDeclaredMethod("jumpToGoodsDetail", new Class[]{String.class, String.class});
- Annotation[] annotations1 = method.getAnnotations();// 获取所有的方法注解信息
- Annotation annotation1 = 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();// 获取方法的返回类型
- int modifiers = method.getModifiers();// 获取方法的访问权限
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- }
反射机制的应用场景:
逆向代码 , 例如反编译
与注解相结合的框架 例如 Retrofit
单纯的反射机制应用框架 例如 EventBus 2.x
动态生成类框架 例如 Gson
反射机制的优缺点:
优点: 运行期类型的判断, 动态类加载, 动态代理使用反射
缺点: 性能是一个问题, 反射相当于一系列解释操作, 通知 jvm 要做的事情, 性能比直接的 java 代码要慢很多
总结:
Java 的反射机制在平时的业务开发过程中很少使用到, 但是在一些基础框架的搭建上应用非常广泛, 今天简单的总结学习了一下, 还有很多未知的知识等以后用到再做补充
来源: http://www.phperz.com/article/18/0212/359372.html