Spring6 - (11) 反射机制

image-20230206074352715

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);

    }
}

执行程序

image-20230320165257053

3. 分析四大要素

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

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

image-20230320165828105

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);
    }
}

运行程序结果

image-20230320170850058

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

image-20230320174010687

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.运行结果

image-20230320172605844

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);
    }
}

运行程序:

image-20230320184030496

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值