springboot 反射出的对象 spring哪里用到了反射_java


文章目录

  • Spring6 -(11)反射机制
  • 1. 反射的简介
  • 2. 不使用反射机制调用一个方法
  • 3. 分析四大要素
  • 4. 使用反射机制调用一个方法
  • 5. 反射机制分析
  • 5. SpringDI核心实现


Spring6 -(11)反射机制

Spring框架的依赖注入底层是通过反射实现的

1. 反射的简介

Java反射机制(Java Reflection)是Java语言中一种动态(运行时)访问、检测、修改它本身的能力,主要作用是动态(运行时)获取类的完整结构信息和调用对象的方法。

更简单点的说就是Java程序在运行时(动态)通过创建一个类的反射对象,再对类进行相关操作,比如:

  • 获取该对象的成员变量或者赋值
  • 调用该对象的方法(含构造方法,有参/无参)
  • 判断该对象所属的类

一般情况下,我们使用某个类,都会知道这个类,以及要用它来做什么,可以直接通过new实例化创建对象,然后使用这个对象对类进行操作,这个就属于正射。

而反射则是一开始并不知道要初始化的是什么类,无法使用new来实例化创建对象,主要是通过JDK提供的反射API来实现,在运行时才知道要操作的是什么类,并且可以获取到类的完整构造以及调用对应的方法,这就是反射。

2. 不使用反射机制调用一个方法

我们先来看一下,不使用反射机制调用一个方法需要几个要素的参与。

定义一个类:

package com.julissa.reflect;

public class SystemService {
    public void logout(){
        System.out.println("退出系统");
    }

    public int show(int number){
        System.out.println("要公布的数字是:" + number);
        return number;
    }
    public String login(String username, String password){
        System.out.println("用户名:" + username);
        System.out.println("密码:" + password);
        return "登录成功";
    }
}

编写程序调用方法:

package com.julissa.reflect;

public class Test {
    public static void main(String[] args) {
        // 创建对象
        SystemService systemService = new SystemService();

        // 调用方法并接收方法的返回值
        String result = systemService.login("admin", "admin123");
        System.out.println(result);

    }
}

执行程序

springboot 反射出的对象 spring哪里用到了反射_spring_02

3. 分析四大要素

通过以上代码可以看出,调用一个方法,一般涉及到4个要素:

  • 调用哪个对象的(systemService)
  • 哪个方法(login)
  • 传什么参数(“admin”, “admin123”)
  • 返回什么值(result)

springboot 反射出的对象 spring哪里用到了反射_java_03

4. 使用反射机制调用一个方法

还是上面的那个类:

package com.julissa.reflect;

public class SystemService {
    public void logout(){
        System.out.println("退出系统");
    }

    public int show(int number){
        System.out.println("要公布的数字是:" + number);
        return number;
    }
    public String login(String username, String password){
        System.out.println("用户名:" + username);
        System.out.println("密码:" + password);
        return "登录成功";
    }
}

编写程序通过反射调用方法:

package com.julissa.reflect;

import java.lang.reflect.Method;

public class Test2 {
    public static void main(String[] args) throws Exception{
        //获取类
        Class<?> clazz = Class.forName("com.julissa.reflect.SystemService");

        //获取方法
        Method loginMethod = clazz.getMethod("login",String.class,String.class);

        //获取对象
        Object obj = clazz.newInstance();

        //调用方法
        //四大要素:调用哪个对象,哪个方法,参数是什么,返回值是什么
        //对象:obj
        //方法:loginMethod
        //参数:"admin", "123456"
        //返回值:result
        Object result = loginMethod.invoke(obj, "admin", "123456");
        System.out.println(result);
    }
}

运行程序结果

springboot 反射出的对象 spring哪里用到了反射_springboot 反射出的对象_04

5. 反射机制分析

要使用反射机制调用一个方法,就关联到四要素:

  • 调用哪个对象的
  • 哪个方法
  • 传什么参数
  • 返回什么值

1。在获取哪个对象或方法之前,首先你需要获取这个类Class。

//获取类
Class<?> clazz = Class.forName("com.julissa.reflect.SystemService");

2.需要创建一个对象,调用哪个对象的方法,当拿到Class之后,调用newInstance可以创建一个对象

Object obj = clazz.newInstance();

或者

Constructor<?> constructor = clazz.getConstructor();
Object obj = constructor.newInstance();

3.当拿到Class之后,调用getDeclaredMethod()方法可以获取到方法。

假如你要获取这个方法:login(String username, String password)

//获取方法
Method loginMethod = clazz.getMethod("login",String.class,String.class);

获取一个方法,需要告诉Java程序,你要获取的方法的名字是什么,这个方法上每个形参的类型是什么。这样Java程序才能给你拿到对应的方法。

因为在同一个类当中,方法是支持重载的,也就是说方法名可以一样,但参数列表一定是不一样的,所以获取一个方法需要提供方法名以及每个形参的类型。

假如你要获取到这个方法:show(int number)

Method showMethod = clazz.getMethod("show",int.class);

假如你要获取到这个方法:logout()

Method logoutMethod = clazz.getMethod("logout");

因为这个方法形式参数的个数是0个。所以只需要提供方法名就行了

4.调用方法,Method对象的invoke()方法可以调用方法

Object result = loginMethod.invoke(obj, "admin", "123456");

解说四要素:

  • 哪个对象:obj
  • 哪个方法:loginMethod
  • 传什么参数:“admin”, “123456”
  • 返回什么值:result

springboot 反射出的对象 spring哪里用到了反射_java_05

5.测试程序

public class Test2 {
    public static void main(String[] args) throws Exception{

        Class<?> clazz = Class.forName("com.julissa.reflect.SystemService");

        Method loginMethod = clazz.getMethod("login",String.class,String.class);

        Object obj = clazz.newInstance();

        Object result = loginMethod.invoke(obj, "admin", "123456");
        System.out.println(result);
    }
}

6.运行结果

springboot 反射出的对象 spring哪里用到了反射_jvm_06

5. SpringDI核心实现

需求:

假如你现在已知以下信息:

1.有这样一个类,类名叫做coM.julissa.reflect.User

2.这个类符合javabean规范(属性私有化,对外提供setter和getter方法)

3.这个类中有一个属性,属性名叫做age

请使用反射机制调用set方法,给User对象的age属性赋值

编写程序:

package com.julissa.reflect;

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

public class Test3 {
    public static void main(String[] args) throws Exception {

        String className = "com.julissa.reflect.User";// 已知类名
        String propertyName = "age"; // 已知属性名
        //获取类
        Class<?> clazz = Class.forName(className);

        //获取属性age的类型
        Field field = clazz.getDeclaredField("age");

        //获取set方法名
        String setMethodName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);

        //获取set方法 field.getType()获取类型的字节码类型 int.class
        Method setMethod = clazz.getMethod(setMethodName, field.getType());

        //获取对象
        Object obj = clazz.newInstance();

        //调用方法,给age属性赋值
        setMethod.invoke(obj, 18);

        System.out.println(obj);
    }
}

运行程序:

springboot 反射出的对象 spring哪里用到了反射_jvm_07