Spring学习记录之回顾反射机制
Spring学习记录之回顾反射机制
前言
这篇文章是我第二次学习b站老杜的spring
相关课程所进行的学习记录
,算是对课程内容及笔记的二次整理,以自己的理解方式进行二次记录,其中理解可能存在错误,欢迎且接受各位大佬们的批评指正;
关于本笔记,只是我对于相关知识遗忘时快速查阅了解使用,至于课程中实际实验配置等,也只是记录关键,并不会记录详细步骤,若想了解可以关注我博客的项目经验模块,我会在实际项目开发过程中总结项目经验,在该模块发布!
学习视频地址:https://www.bilibili.com/video/BV1Ft4y1g7Fb/
视频配套笔记:https://www.yuque.com/dujubin/ltckqu/kipzgd?singleDoc# 《Spring6》 密码:mg9b
目录
一、我个人对这部分学习的一些见解
Java反射机制这部分在学习Java基础时就是需要熟练掌握的内容,这里大家可以跟随老杜的笔记来回顾一下反射机制。
这部分我会继续引用老杜的笔记。
二、回顾反射机制
① 分析调用方法四要素
我们先来看一下,不使用反射机制调用一个方法需要几个要素的参与。
有一个这样的类:
SystemService
package com.powernode.reflect;
/**
* @author 动力节点
* @version 1.0
* @className SystemService
* @since 1.0
**/
public class SystemService {
public void logout(){
System.out.println("退出系统");
}
public boolean login(String username, String password){
if ("admin".equals(username) && "admin123".equals(password)) {
return true;
}
return false;
}
}
编写程序调用方法:
ReflectTest01
package com.powernode.reflect;
/**
* @author 动力节点
* @version 1.0
* @className ReflectTest01
* @since 1.0
**/
public class ReflectTest01 {
public static void main(String[] args) {
// 创建对象
SystemService systemService = new SystemService();
// 调用方法并接收方法的返回值
boolean success = systemService.login("admin", "admin123");
System.out.println(success ? "登录成功" : "登录失败");
}
}
执行结果:
总结:
通过以上实验可以看出,调用一个方法,一般涉及到4个要素:
- 调用哪个对象的方法,先确定对象(
systemService
) - 然后调用该对象的哪个方法(
login
) - 给该方法传什么参数(
"admin", "admin123"
) - 最后考虑该方法的返回值是什么(
success
)
② 反射机制获取Method(类方法)
要使用反射机制调用一个方法,首先你要获取到这个方法。
在反射机制中Method
实例代表的是一个方法。那么怎么获取Method实例呢?
有这样一个类:
SystemService
package com.powernode.reflect;
/**
* @author 动力节点
* @version 1.0
* @className SystemService
* @since 1.0
**/
public class SystemService {
public void logout(){
System.out.println("退出系统");
}
public boolean login(String username, String password){
if ("admin".equals(username) && "admin123".equals(password)) {
return true;
}
return false;
}
public boolean login(String password){
if("110".equals(password)){
return true;
}
return false;
}
}
我们如何获取到 logout()
、login(String,String)
、login(String)
这三个方法呢?
要获取方法Method
,首先你需要获取这个类Class
。
获取类Class
的代码:
Class clazz = Class.forName("com.powernode.reflect.SystemService");
补充:Java
可以读取类文件,将该类文件信息封装成一个Class
类的对象实例。这样我们在只有类路径的情况下,就可以直接操作该类文件,创建该类的对象,调用该对象的方法。这个过程就是所谓的"反射"。
当拿到Class
之后,调用getDeclaredMethod()
方法可以获取到方法。
假如你要获取这个方法:login(String username, String password)
Method loginMethod = clazz.getDeclaredMethod("login", String.class, String.class);
假如你要获取到这个方法:login(String password)
Method loginMethod = clazz.getDeclaredMethod("login", String.class);
获取一个方法,需要告诉Java
程序,你要获取的方法的名字是什么,这个方法上每个形参的类型是什么。这样Java
程序才能给你拿到对应的方法。
这样的设计也非常合理,因为在同一个类当中,方法是支持重载的,也就是说方法名可以一样,但参数列表一定是不一样的,所以获取一个方法需要提供方法名以及每个形参的类型。
假设有这样一个方法:
public void setAge(int age){
this.age = age;
}
你要获取这个方法的话,代码应该这样写:
Method setAgeMethod = clazz.getDeclaredMethod("setAge", int.class);
其中setAge
是方法名,int.class
是形参的类型。
如果要获取上面的logout
方法,代码应该这样写:
Method logoutMethod = clazz.getDeclaredMethod("logout");
因为这个方法形式参数的个数是0个。所以只需要提供方法名就行了。你学会了吗?
到这里,你是不是隐约能感觉到Spring
读取xml
配置文件后是如何实例化对象并通过属性对应的set
方法给对象赋值的。
③ 反射机制调用Method(类方法)
要让一个方法调用的话,就关联到四要素了:
- 调用哪个对象的
- 哪个方法
- 传什么参数
- 返回什么值
SystemService
package com.powernode.reflect;
/**
* @author 动力节点
* @version 1.0
* @className SystemService
* @since 1.0
**/
public class SystemService {
public void logout(){
System.out.println("退出系统");
}
public boolean login(String username, String password){
if ("admin".equals(username) && "admin123".equals(password)) {
return true;
}
return false;
}
public boolean login(String password){
if("110".equals(password)){
return true;
}
return false;
}
}
假如我们要调用的方法是:login(String, String)
第一步:创建对象(四要素之首:调用哪个对象的)
Class clazz = Class.forName("com.powernode.reflect.SystemService");
Object obj = clazz.newInstance();
第二步:获取方法login(String,String)
(四要素之一:哪个方法)
Method loginMethod = clazz.getDeclaredMethod("login", String.class, String.class);
第三步:调用方法
Object retValue = loginMethod.invoke(obj, "admin", "admin123");
解说四要素:
- 哪个对象:
obj
- 哪个方法:
loginMethod
- 传什么参数:
"admin", "admin123"
- 返回什么值:
retValue
测试程序:
package com.powernode.reflect;
import java.lang.reflect.Method;
/**
* @author 动力节点
* @version 1.0
* @className ReflectTest02
* @since 1.0
**/
public class ReflectTest02 {
public static void main(String[] args) throws Exception{
Class clazz = Class.forName("com.powernode.reflect.SystemService");
Object obj = clazz.newInstance();
Method loginMethod = clazz.getDeclaredMethod("login", String.class, String.class);
Object retValue = loginMethod.invoke(obj, "admin", "admin123");
System.out.println(retValue);
}
}
执行结果:
那如果调用既没有参数,又没有返回值的logout
方法,应该怎么做?
package com.powernode.reflect;
import java.lang.reflect.Method;
/**
* @author 动力节点
* @version 1.0
* @className ReflectTest03
* @since 1.0
**/
public class ReflectTest03 {
public static void main(String[] args) throws Exception{
Class clazz = Class.forName("com.powernode.reflect.SystemService");
Object obj = clazz.newInstance();
Method logoutMethod = clazz.getDeclaredMethod("logout");
logoutMethod.invoke(obj);
}
}
执行结果:
④ 思考:假设已知类属性名
假设有这样一个类:
User
package com.powernode.reflect;
/**
* @author 动力节点
* @version 1.0
* @className User
* @since 1.0
**/
public class User {
private String name;
private int age;
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 "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
你知道以下这几条信息:
-
类名是:
com.powernode.reflect.User
-
该类中有
String
类型的name
属性和int
类型的age
属性。 -
另外你也知道该类的设计符合
javabean
规范。(也就是说属性私有化,对外提供setter
和getter
方法)
你如何通过反射机制给User
对象的name
属性赋值zhangsan
,给age
属性赋值20岁。
package com.powernode.reflect;
import java.lang.reflect.Method;
/**
* @author 动力节点
* @version 1.0
* @className UserTest
* @since 1.0
**/
public class UserTest {
public static void main(String[] args) throws Exception{
// 已知类名
String className = "com.powernode.reflect.User";
// 已知属性名
String propertyName = "age";
// 通过反射机制给User对象的age属性赋值20岁
Class<?> clazz = Class.forName(className);
Object obj = clazz.newInstance(); // 创建对象
// 根据属性名获取setter方法名
String setMethodName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);
// 获取Method
Method setMethod = clazz.getDeclaredMethod(setMethodName, int.class);
// 调用Method
setMethod.invoke(obj, 20);
System.out.println(obj);
}
}
执行结果:
给User
的name
属性赋值zhangsan
,这个大家可以尝试自己完成哦!!!
到这里,你是不是更有感觉了呢?
三、总结
这部分我们回顾了Java
反射机制相关知识,同时通过举例的方式,让大家模糊的感觉到Spring
如何实现依赖注入等操作。下节我们将学习手写Spring
框架,来更深刻的体会一下Spring
的底层原理。
这里需要去了解老杜这节相关讲解,可以直接点击下面链接跳转到对应课程学习了解!