JAVA的反射机制

217 阅读6分钟

「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战

1.基础概念

<1>反射机制概念

反射的引入

Object obj = new User();
若程序运行时接收到外部传入的一个对象,该对象的编译类型是Object,但程序又需要调用该对象运行类型的方法:
1.若编译和运行类型都知道,使用 instanceof判断后进行强制类型转化
2.编译时根本无法预知该对象属于什么类,程序只能依靠运行时信息来发现对象的真实信息,需要用到反射
3.需要得到对象真正的类型,需要用到反射

反射机制的定义

​ Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的以及动态调用对象的方法的功能称为Java的反射机制

​ 简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息

反射机制的优缺点

​ 从“动态”、“静态”的方向分析反射机制的优缺点

​ 静态编译:在编译时确定类型,绑定对象,即通过

​ 动态编译:在运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,用以降低类之间的藕合性

​ 反射机制的优点就是可以实现动态创建对象和编译,具备灵活性(在J2EE开发中可体现),运行期类型的判断、动态类加载、动态代理使用反射;缺点在于对程序的性能有影响(使用反射基本上是一种解释操作,告知JVM要做的事情,这类操作总是慢于只直接执行相同的操作)

反射机制能够获取的信息

在运行时判定任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判定任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;
生成动态代理;

主要的反射机制类:

java.lang.Class; //类               
java.lang.reflect.Constructor;//构造方法 
java.lang.reflect.Field; //类的成员变量       
java.lang.reflect.Method;//类的方法
java.lang.reflect.Modifier;//访问权限

<2>Class类和Class类实例

Class相关概念

​ Java程序中的各个Java类属于同一类事物,描述这类事物的Java类就是Class类

​ 一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的(一个类在虚拟机中只有一份字节码);

反射就是得到元数据的行为

​ 用类来描述对象(类:描述数据的结构);用元数据来描述Class(MetaData(元数据):描述数据结构的结构)

class对象的获取

// 方式1:通过对象getClass方法
Person person = new Person();
Class<?> class1 = person.getClass();
// 方式2:通过类的class属性
class1 = Person.class;
try {
    // 方式3:通过Class类的静态方法forName()来实现
    class1 = Class.forName("club.sscai.Person");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

获取class对象的属性、方法、构造函数等

// 获取class对象的所有属性
Field[] allFields = class1.getDeclaredFields();

// 获取class对象的public属性
Field[] publicFields = class1.getFields();
try {
    // 获取class指定属性
    Field ageField = class1.getDeclaredField("age");
    // 获取class指定的public属性
    Field desField = class1.getField("des");
} catch (NoSuchFieldException e) {
    e.printStackTrace();
}

// 获取class对象的所有声明方法
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对象public构造函数
Constructor<?>[] publicConstructors = class1.getConstructors();

try {
    // 获取指定声明构造函数
    Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{String.class});
    // 获取指定声明的public构造函数
    Constructor publicConstructor = class1.getConstructor(new Class[]{});
} catch (NoSuchMethodException e) {
    e.printStackTrace();
}
// 获取class对象的所有注解
Annotation[] annotations = class1.getAnnotations();

// 获取class对象指定注解
Annotation annotation = class1.getAnnotation(Deprecated.class);

// 获取class对象的直接超类的 Type
Type genericSuperclass = class1.getGenericSuperclass();

// 获取class对象的所有接口的type集合
Type[] interfaceTypes = class1.getGenericInterfaces();

2.功能应用

<1>通过反射机制获取泛型类型

示例

// People类
public class People<T> {}
//Person类继承People类
public class Person<T> extends People<String> implements PersonInterface<Integer> {}
//PersonInterface接口
public interface PersonInterface<T> {}

获取泛型类型

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;
}
Person<String> person = new Person<>();
// 方式1:通过对象getClass方法
Class<?> class1 = person.getClass();
Type genericSuperclass = class1.getGenericSuperclass();// 获取class对象的直接超类的 Type
Type[] interfaceTypes = class1.getGenericInterfaces();// 获取class对象的所有接口的Type集合
getComponentType(genericSuperclass);
getComponentType(interfaceTypes[0]);

<2>通过反射机制获取注解信息

​ 通过反射机制获取注解信息再AOP中经常使用

try {
    // 首先需要获得与该方法对应的Method对象
    Method method = class1.getDeclaredMethod("methodName", 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类型
    Class<?>[] parameterTypes = method.getParameterTypes();
    // 获取所有参数的type类型
    Type[] genericParameterTypes = method.getGenericParameterTypes();
    // 获取方法的返回类型
    Class<?> returnType = method.getReturnType();
    // 获取方法的访问权限
    int modifiers = method.getModifiers();
} catch (NoSuchMethodException e) {
    e.printStackTrace();
}

3.应用实例

比较两个实体对象的信息

​ 分析说明:针对两个对象,Member 和 MemberView,需要进行相应的转化,通常使用的方式是把通过手动get、set操作实现,当对象属性较多的时候,代码或显得臃肿

public class TestClass{
    public double eachOrtherToAdd(Integer one,Double two,Integer three){
        return one + two + three;
    }
}
public class ReflectionDemo{

    public static void main(String args[]){
        String className = "initLoadDemo.TestClass";
        String methodName = "eachOrtherToAdd";
        String[] paramTypes = new String[]{"Integer","Double","int"};
        String[] paramValues = new String[]{"1","4.3321","5"};

        // 动态加载对象并执行方法
        initLoadClass(className, methodName, paramTypes, paramValues);

    }

    @SuppressWarnings("rawtypes")
    private static void initLoadClass(String className,String methodName,String[] paramTypes,String[] paramValues){
        try{
            // 根据calssName得到class对象
            Class cls = Class.forName(className);

            // 实例化对象
            Object obj = cls.newInstance();

            // 根据参数类型数组得到参数类型的Class数组
            Class[] parameterTypes = constructTypes(paramTypes);

            // 得到方法
            Method method = cls.getMethod(methodName, parameterTypes);

            // 根据参数类型数组和参数值数组得到参数值的obj数组
            Object[] parameterValues = constructValues(paramTypes,paramValues);

            // 执行这个方法并返回obj值
            Object returnValue = method.invoke(obj, parameterValues);

            System.out.println("结果:"+returnValue);

        }catch (Exception e){
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private static Object[] constructValues(String[] paramTypes,String[] paramValues){
        Object[] obj = new Object[paramTypes.length];
        for (int i = 0; i < paramTypes.length; i++){
            if(paramTypes[i] != null && !paramTypes[i].trim().equals("")){
                if ("Integer".equals(paramTypes[i]) || "int".equals(paramTypes[i])){
                    obj[i] = Integer.parseInt(paramValues[i]);
                }else if ("Double".equals(paramTypes[i]) || "double".equals(paramTypes[i])){
                    obj[i] = Double.parseDouble(paramValues[i]);
                }else if ("Float".equals(paramTypes[i]) || "float".equals(paramTypes[i])){
                    obj[i] = Float.parseFloat(paramValues[i]);
                }else{
                    obj[i] = paramTypes[i];
                }
            }
        }
        return obj;
    }

    @SuppressWarnings("rawtypes")
    private static Class[] constructTypes(String[] paramTypes){
        Class[] cls = new Class[paramTypes.length];
        for (int i = 0; i < paramTypes.length; i++){
            if(paramTypes[i] != null && !paramTypes[i].trim().equals("")){
                if ("Integer".equals(paramTypes[i]) || "int".equals(paramTypes[i])){
                    cls[i] = Integer.class;
                }else if ("Double".equals(paramTypes[i]) || "double".equals(paramTypes[i])){
                    cls[i] = Double.class;
                }else if ("Float".equals(paramTypes[i]) || "float".equals(paramTypes[i])){
                    cls[i] = Float.class;
                }else{
                    cls[i] = String.class;
                }
            }
        }
        return cls;
    }
}