1. 问题描述
这里我们使用 java 的反射特性,完成几个简单的例子,用于学习总结。
2. 准备工作
创建一个类,含有属性和方法,用于接下来我们通过反射创建它的对象,调用它的方法,修改它的属性。
package cn.smileyan.reflex.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Map;
/**
* Student 类 用于测试
* @author Smileyan
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private Integer age = 0;
private String name = "Tom";
public void say(String msg) {
System.out.printf("%s %d %s\n", name, age, msg);
}
public void say() {
System.out.printf("%s %d\n", name, age);
}
private void secret() {
System.out.printf("%s %d 私有方法\n", name, age);
}
public void walk(String way, Integer distance) {
System.out.printf("%s %d %s %d\n", name, age, way, distance);
}
public void walk(Map<String, Object> params) {
walk(params.get("way").toString(), (Integer) params.get("distance"));
}
}
3. 使用 java 原生的方法
3.1 构造方法
- 使用字符串(类的路径)创建类,再通过newInstance创建对象。
// 1.1 通过字符串获得类,并创建对象(不穿参数),再调用两个public方法 Class<Student> clazz1 = (Class<Student>) Class.forName("cn.smileyan.reflex.entity.Student"); Student student1 = clazz1.getConstructor().newInstance(); student1.say(); student1.say("reflex1");
- 通过字符串构建类,并创建对象(传参),再调用两个public方法
// 1.2 通过字符串构建类,并创建对象(传参),再调用两个public方法 Class<Student> clazz2 = (Class<Student>) Class.forName("cn.smileyan.reflex.entity.Student"); Student student2 = clazz2.getConstructor(Integer.class, String.class).newInstance(2, "Jerry"); student2.say(); student2.say("reflex2");
- 通过类.class创建实体(推荐)
// 1.3 通过类创建实体 Class<Student> clazz3 = Student.class; Student student3 = clazz3.getConstructor(Integer.class, String.class).newInstance(3, "Jack"); student3.say(); student3.say("reflex3");
3.2 通过反射调用类的对象的方法
- 通过字符串不创建实体类而是通过方法名调用方法
// 1.4 通过字符串不创建实体类而是通过方法名调用方法 Class<?> clazz4 = Class.forName("cn.smileyan.reflex.entity.Student"); Method method4 = clazz4.getDeclaredMethod("say"); System.out.println("方法名:" + method4.getName() + " 方法返回类型" + method4.getReturnType()); System.out.println();
- 通过字符串不创建实体类而是通过方法名调用方法,并传入参数。
// 1.5 通过反射调用对象的某个方法 Student student5 = new Student(); Class<Student> clazz5 = Student.class; Method method5 = clazz5.getDeclaredMethod("say", String.class); method5.invoke(student5, "reflex5"); System.out.println();
4. 使用 ReflectASM 反射方法
添加依赖:
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>reflectasm</artifactId>
<version>1.11.9</version>
</dependency>
// 1. 创建对象
ConstructorAccess<Student> constructor1 = ConstructorAccess.get(Student.class);
Student student1 = constructor1.newInstance();
student1.say();
System.out.println();
// 2. 调用方法
Student student2 = new Student();
MethodAccess methodAccess1 = MethodAccess.get(Student.class);
methodAccess1.invoke(student2, "setName", "Awesome McLovin");
methodAccess1.invoke(student2, "say");
System.out.println();
其他的地方相差不大。
注意
: 两种方法中均需要注意,如果掉用 private 方法,或者访问 private 属性,需要设置
method.setAccessible(true);
5. 总结
反射还会有更多的应用场景,这里只是简单的记录一下,今后收集到更多案例再进行补充。
Smileyan
2023.03.14 23:23