何为反射
Java的反射(reflection)机制是指在程序运行中, 你可以通过反射获取任意一个类的所有属性和方法,还可以调用任意一个对象的属性和方法。反射在很多框架中被使用,像 Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制。Java注解也使用到了反射。
聊聊反射机制的优缺点
优点:可以让咱们的代码更加灵活,为各种框架提供开箱即用的功能提供了便利
缺点:让我们在运行时可以获取类信息的能力,这样增加了安全问题。反射的性能也要稍差点,不过,对于框架来说实际是影响不大的。
获取Class对象的四种方式
我们需要依靠Class对象来动态获取类的信息,Class 类对象将一个类的方法、变量等信息告诉运行的程序。所以我们要先知道如何获取Class对象,Java有四种方式获取 Class 对象。
// 1. 已知具体类的情况下获取Class对象
Class cls1 = Person.class;
// 2. 通过对象实例instance.getClass()获取Class对象
Person p = new Person();
Class cls2 = p.getClass();
// 3. 通过Class.forName()传入类的全路径获取Class对象
Class cls3 = Class.forName("com.jms.reflection.Person");
// 4. 通过类加载器xxxClassLoader.loadClass()传入类路径获取Class对象
ClassLoader.getSystemClassLoader().loadClass("com.jms.reflection.Person");
玩转反射
- 首先写个反射操作类
package com.jms.reflection;
public class Person {
private Integer age;
private String name;
private String sex;
public Person() {
}
public Person(Integer age, String name, String sex) {
this.age = age;
this.name = name;
this.sex = sex;
}
/**
* 打印信息(公共方法)
* @param remark 备注
*/
public void publicInfo(String remark) {
System.out.println("person: name=" + name + ", sex=" + sex + ", age=" + age + ", remark=" + remark);
}
/**
* 打印信息(私有方法)
* @param remark 备注
*/
private void privateInfo(String remark) {
System.out.println("person: name=" + name + ", sex=" + sex + ", age=" + age + ", remark=" + remark);
}
/**
* 打印信息(静态方法)
* @param person 个人信息
*/
public static void staticInfo(Person person) {
if (person == null) {
return;
}
System.out.println("person: name=" + person.name + ", sex=" + person.sex + ", age=" + person.age);
}
}
2.写个测试类玩转反射
package com.jms.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class RefTest {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException,
IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
// 1. 获取Person类Class对象
Class<?> cls = Class.forName("com.jms.reflection.Person");
// 2. 创建Person对象
Constructor<?> constructor = cls.getDeclaredConstructor(Integer.class, String.class, String.class);
Person p = (Person) constructor.newInstance(18, "吴签", "男");
// 3. 获取所有构造函数
Constructor[] constructors = cls.getDeclaredConstructors();
System.out.println("构造函数:");
for (Constructor c : constructors) {
System.out.println(c.getName() + " - " + c.getGenericParameterTypes().length + " 参数");
}
// 4. 获取Person类中定义的所有方法
Method[] methods = cls.getDeclaredMethods();
System.out.println("\n方法:");
for (Method method : methods) {
System.out.println(method.getName());
}
// 5. 获取Person类中定义的成员变量
Field[] fields = cls.getDeclaredFields();
System.out.println("\n成员变量:");
for (Field field : fields) {
System.out.println(field.getName());
}
// 6. 调用公共方法
Method publicMethod = cls.getDeclaredMethod("publicInfo",
String.class);
System.out.println("\n调用公共方法:");
publicMethod.invoke(p, "公共方法测试");
// 7. 调用私有方法
Method privateMethod = cls.getDeclaredMethod("privateInfo",
String.class);
privateMethod.setAccessible(true); // 取消安全检查
System.out.println("\n调用私有方法:");
privateMethod.invoke(p, "私有方法测试");
// 8.修改参数
Field field = cls.getDeclaredField("name");
field.setAccessible(true); // 对类中的私有变量进行修改要取消安全检查
field.set(p, "马户又鸟");
// 9. 调用静态方法
Method staticMethod = cls.getDeclaredMethod("staticInfo",
Person.class);
System.out.println("\n调用静态方法:");
staticMethod.invoke(null, p);
}
}
3.输出内容
构造函数:
com.jms.reflection.Person - 0 参数
com.jms.reflection.Person - 3 参数
方法:
publicInfo
staticInfo
privateInfo
成员变量:
age
name
sex
调用公共方法:
person: name=吴签, sex=男, age=18, remark=公共方法测试
调用私有方法:
person: name=吴签, sex=男, age=18, remark=私有方法测试
调用静态方法:
person: name=马户又鸟, sex=男, age=18