当前位置: 首页 > article >正文

什么是反射,反射用途,spring哪些地方用到了反射,我们项目中哪些地方用到了反射

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赋值。


http://www.kler.cn/a/317091.html

相关文章:

  • ssm114基于SSM框架的网上拍卖系统的设计与实现+vue(论文+源码)_kaic
  • Android 13 实现屏幕熄屏一段时候后关闭 Wi-Fi 和清空多任务列表
  • UAC2.0 speaker——同时支持 16bit,24bit 和 32bit
  • [JAVAEE] 面试题(四) - 多线程下使用ArrayList涉及到的线程安全问题及解决
  • 闯关leetcode——3178. Find the Child Who Has the Ball After K Seconds
  • 2411d,右值与移动
  • 【python】requests 库 源码解读、参数解读
  • Maven笔记(一):基础使用【记录】
  • Spring Boot 中的拦截器 Interceptors
  • 【已解决】用JAVA代码实现递归算法-从自然数中取3个数进行组合之递归算法-用递归算法找出 n(n>=3) 个自然数中取 3 个数的组合。
  • 在云渲染中3D工程文件安全性怎么样?
  • 【HarmonyOS】深入理解@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化
  • Unity-Screen屏幕相关
  • 【设计模式】万字详解:深入掌握五大基础行为模式
  • 鸿蒙 OS 开发零基础快速入门教程
  • ER论文阅读-Incomplete Multimodality-Diffused Emotion Recognition
  • 【LLM学习之路】9月22日 第九天 自然语言处理
  • 计算一个矩阵的逆矩阵的方法
  • 2024ICPC网络赛第一场C. Permutation Counting 4(线性代数)
  • nginx的反向代理和负载均衡
  • 16.3 k8s容器cpu内存告警指标与资源request和limit
  • 【数据结构-栈】力扣682. 棒球比赛
  • 0-1开发自己的obsidian plugin DAY 1
  • 鸿蒙操作系统(HarmonyOS)生态与机遇
  • YOLOv10改进,YOLOv10替换主干网络为PP-HGNetV1(百度飞桨视觉团队自研,全网首发,助力涨点)
  • watch和computed的使用及区别