文章目录
- 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);
}
}
执行程序
3. 分析四大要素
通过以上代码可以看出,调用一个方法,一般涉及到4个要素:
- 调用哪个对象的(systemService)
- 哪个方法(login)
- 传什么参数(“admin”, “admin123”)
- 返回什么值(result)
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);
}
}
运行程序结果
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
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.运行结果
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);
}
}
运行程序: