3分钟搞懂Java反射
一、反射是什么
在Java中,反射(Reflection)是一种强大的工具,它允许程序在运行时获取和操作类、接口、构造器、方法和字段等。反射是Java语言的一个重要特性,它为开发人员提供了许多灵活性,尤其是在构建框架和库时非常有用。
二、获取Class对象的三种方式
1.Class c1 =类名.class
public class MyClass {public static void main(String[] args) {Class<?> myClass = MyClass.class; // 获取 MyClass 的 Class 对象System.out.println(myClass.getName()); // 输出: com.beiyou.example.MyClass}
}
2.通过 instance.getClass()
方法,如果你有一个类的实例,你可以调用 getClass()
方法来获取其 Class
对象
public class MyClass {public static void main(String[] args) {MyClass instance = new MyClass();Class<?> myClass = instance.getClass(); // 获取 MyClass 实例的 Class 对象System.out.println(myClass.getName()); // 输出: com.beiyou.example.MyClass}
}
3.通过 Class.forName()
方法,通过全类名动态加载类,并获取其 Class
对象
public class MyClass {public static void main(String[] args) throws ClassNotFoundException {Class<?> myClass = Class.forName("com.example.MyClass"); // 动态加载 MyClass 的 Class 对象System.out.println(myClass.getName()); // 输出: com.example.MyClass}
}
Java
三、反射的主要用途包括
1.获取类信息:获取类名、包名、父类、接口等。
获取类名:myClass.getName()
获取类的属性:c1.getField(),只能获取public修饰的属性,getDeclaredField(),获取任意修饰符修饰的属性
获取方法:c1.getMethod(),只能获取public的方法,getDeclaredMethodes()获取任意修饰符修饰的方法,
2.创建实例:通过类名或Class对象动态创建实例。
3.访问类成员:获取并操作类的字段、方法和构造器。
也可以使用 Hutool 中的ReflectUtil
类中的方法来操作类的方法和属性。使用Hutool前记得引用Hutool
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.26</version>
</dependency>
例子:首先创建一个基类
import lombok.Data;@Data
public class Student {public int id;public String name;private int age;public Student() {}public Student(int id, String name, int age) {this.id = id;this.name = name;this.age = age;System.out.println("这是构造");}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}public void say() {System.out.println("hello++++++");}public void eat() {System.out.println("吃饭------");}
}
测试类test1
import cn.hutool.core.util.ReflectUtil;
import com.beiyou.model.Student;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;@SpringBootTest
class RefleUtilAppTests {//创建实例Student student = ReflectUtil.newInstance(Student.class, 1, "张三", 18);@Testvoid test1() {//构造Constructor<Student> constructor = ReflectUtil.getConstructor(Student.class);// 获取字段Field field = ReflectUtil.getField(Student.class, "name");
// Map<String, Field> fieldMap = ReflectUtil.getFieldMap(Student.class);//获取所有字段Field[] fields = ReflectUtil.getFields(Student.class);//设置字段值ReflectUtil.setFieldValue(student, "name", "李四");//获取指定字段值Object fieldValue = ReflectUtil.getFieldValue(student, "name");}@Testvoid test2() {Student student = ReflectUtil.newInstance(Student.class, 1, "张三", 18);// 获取所有方法Method[] methods = ReflectUtil.getMethods(Student.class);for (Method m : methods) {System.out.println(m.getName());}// 获取指定方法Method method = ReflectUtil.getMethod(Student.class, "say");System.out.println(method.getName());// 执行方法ReflectUtil.invoke(student, "say");}}
测试类2
import cn.hutool.core.util.ReflectUtil;
import com.beiyou.model.Student;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;class ReflectionAppTests {public static void main(String[] args) {Class<?> studentClass = null;try {//获取类对象studentClass = Class.forName("com.beiyou.model.Student");// 获取构造器Constructor<?> constructor = studentClass.getConstructor();//创建实例Object instance = studentClass.newInstance();//获取属性Field name = studentClass.getField("name");name.set(instance, "张三");System.out.println("name : " + name.get(instance));Field age = studentClass.getDeclaredField("age");age.setAccessible(true);age.set(instance, 20);System.out.println(" age : " + age.get(instance));} catch (Exception e) {e.printStackTrace();}}
}
效率:通过new获取对象的操作要比通过反射获取对象速度快得多。根据情况选择使用new还是反射。
四、Spring框架中哪里用到了反射
1. 依赖注入:Spring通常使用反射机制来创建和初始化 Bean。
依赖注入三种方式:构造方法注入,set方法注入和属性注入
2. AOP:代理方式分为动态代理和静态代理,静态代理是我们手写的,动态代理分为Spring动态Spring AOP 使用 JDK 动态代理或者 CGLIB 字节码增强技术来实现 AOP 的切面逻辑,这其中就包含了对被代理对象方法的反射调用。JDK 动态代理适用于实现了接口的目标对象。Spring 使用 java.lang.reflect.Proxy
类来创建代理对象,并且使用 InvocationHandler
接口来定义方法拦截逻辑。
3. MVC 框架:Spring MVC 框架使用反射来调用相应的控制器方法,从而实现请求的处理。
4. 数据库访问框架:Spring 的 JDBC 框架使用反射机制来实现对数据库的访问。
5. 容器管理:Spring 容器也使用了反射机制来管理对象的实例化和依赖注入。
五、我们在项目哪里用到了反射
MyBatis拦截器处理参数时使用,在做WMS仓储系统时,我们的数据表中都有lastUpdatBy这个字段,我们绝大多数业务都需要对lastUpdateBy进行赋值,所以我们就在Mybatis拦截器中通过反射获取参数,然后通过ThreadLocal中的localuser进行统一对其赋值。ThreadLocal为每一个线程提供一个独立的变量副本,使得每个线程在访问变量时获取的都是自己独有的线程副本,ThreadLocal能够实现跨类跨方法实现变量的传递。我们定义了一个LocalUser对象存储在ThreadLocal中,然后就可以获取ThreadLocal中的Localuser对象为lastUpdateBy赋值。