Java反射机制相关知识概述

111 阅读4分钟

反射概念

反射(Reflection)在我们日常开发中无时无刻,被大量运用在框架代码和工具代码中,反射可以通俗点讲就是一个类的自我剖析,通过反射可以获取到这个类所有信息,包括:属性,属性值,方法,构造器等等。

反射机制

  • Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
  • Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。

反射的应用场景反射是框架设计的灵魂,像 Spring/Spring Boot、Mybatis 等等框架中都大量使用了反射机制。

反射的优缺点

  • 优点:可以让咱们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利
  • 缺点:让我们在运行时有了分析操作类的能力,这同样也增加了安全问题。比如可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。另外,反射的性能也要稍差点,不过,对于框架来说实际是影响不大的。

反射常用方法

反射机制相关类

含义
java.lang.Class代表整个字节码。代表一个类型,代表整个类
java.lang.reflect.Method代表字节码中的方法字节码。代表类中的方法
java.lang.reflect.Constructor代表字节码中的构造方法字节码。代表类中的构造方法
java.lang.reflect.Field代表字节码中的属性字节码。代表类中的成员变量

获取Class对象

1. 知道具体类的情况下可以使用xx.class:

Class class1 = TargetObject.class;

2. 通过 Class.forName()传入类的全路径获取:

Class class2 = Class.forName("com.qing.TargetObject");

3. 通过对象实例xx.getClass()获取:

TargetObject targetObject = new TargetObject();
Class class3 = targetObject.getClass();

获取类的构造方法

方法名描述
getConstructors()获取类的全部构造器(只能获取public修饰的)
getDeclaredConstructors()获取类的全部构造器(无视修饰,存在就可获取)
getConstructor(Class...<?> parameterTypes)获取类的某个构造器(只能获取public修饰的)
getDeclaredConstructor(Class...<?> parameterTypes)获取类的某个构造器(无视修饰,存在就可获取)

获取类的成员变量

方法名描述
getFields();获取类的全部成员变量(只能获取public修饰的)
getDeclaredFields();获取类的全部成员变量(无视修饰,存在就可获取)
getField(String name);获取类的某个成员变量(只能获取public修饰的)
getDeclaredField(String name);获取类的某个成员变量(无视修饰,存在就可获取)

获取类的成员方法

方法名描述
getMethods();获取类的全部成员方法(只能获取public修饰的)
getDeclaredMethods();获取类的全部成员方法(无视修饰,存在就可获取)
getMethod(String name, Class...<?> parameterTypes)获取类的某个成员方法(只能获取public修饰的)
getDeclaredMethod(String name, Class...<?> parameterTypes)获取类的某个成员方法(无视修饰,存在就可获取)

访问私有变量或方法

私有变量私有方法对象的 setAccessible(true) 方法设置为true,代表压制Java访问检查,否则会出非法访问异常

field.setAccessible(true);
method.setAccessible(true);

反射相关基本操作实例

  1. 创建一个我们要使用反射操作的类 TargetObject
package com.qing;
public class TargetObject {
    private String value;

    public TargetObject() {
        value = "Qing";
    }

    public void publicMethod(String s) {
        System.out.println("I love " + s);
    }

    private void privateMethod() {
        System.out.println("value is " + value);
    }
}
  1. 使用反射操作这个类的方法以及参数
package com.qing;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {
        /**
         * 获取 TargetObject 类的 Class 对象并且创建 TargetObject 类实例
         */
        Class<?> targetClass = Class.forName("com.qing.TargetObject");
        TargetObject targetObject = (TargetObject) targetClass.newInstance();
        /**
         * 获取 TargetObject 类中定义的所有方法
         */
        Method[] methods = targetClass.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }

        /**
         * 获取指定方法并调用
         */
        Method publicMethod = targetClass.getDeclaredMethod("publicMethod",
                String.class);

        publicMethod.invoke(targetObject, "Qing");

        /**
         * 获取指定参数并对参数进行修改
         */
        Field field = targetClass.getDeclaredField("value");
        //为了对类中的参数进行修改我们取消安全检查
        field.setAccessible(true);
        field.set(targetObject, "Qing");

        /**
         * 调用 private 方法
         */
        Method privateMethod = targetClass.getDeclaredMethod("privateMethod");
        //为了调用private方法我们取消安全检查
        privateMethod.setAccessible(true);
        privateMethod.invoke(targetObject);
    }
}

输出内容:

publicMethod
privateMethod
I love Qing
value is Qing