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;
}
@Override
public 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);
@Test
void 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");
}
@Test
void 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赋值。