反射是什么
官方定义:在运行时可以动态地获取类的信息,并操作类属性和方法的能力**(不需要提前知道这个类的具体细节)**.简单来说,假设你有一个盒子,盒子里装满了玩具.正常的操作是:你已知盒子里是什么玩具,可以直接取出来.反射操作:闭着眼在盒子里摸索,通过形状,重量猜出是什么玩具
反射的作用
- **反射的核心作用:动态性.**反射让程序在运行时动态操作类和对象,而不是在编译时写死代码.就像给程序装了一个"扫描仪",可以实时监测未知的类结构
反射的基础实现:Class对象
Class对象简单来说就是类的"身份证"
-
对于每一个类来说比如(
String,ArrayList
),在JVM中都有一个对应的Class对象,这个Class对象记录了这个类的所有消息包括:类名,方法,字段,构造器等等 -
更加贴切的类比
假设要组装一个电脑
- 类:相当于电脑的设计图纸
- 对象:根据图纸造出的实体电脑
- Class对象:图纸的索引卡片(记录,图纸存放的位置,版本号,需要的零件信息)
若你要查看图纸,不是直接对图纸进行操作,而是通过索引卡片(Class对象)找到图纸信息
获取Class对象的方法
类名.class
java
//类名.class(最直接)
Class<String> stringClass = String.class;
- 明确知道要操作的类,编译时检查类是否存在
对象.getClass()
java
//对象.getClass()
String str = "Hello World";
Class<?> strClass = str.getClass();
- 前提已经存在对象实例,只能获取对象实例类型的Class
Class.forName()
java
//Class.forName("完整类名")最灵活
Class<?> arrayListClass = Class.forName("java.lang.ArrayList");
- 动态加载类(根据配置),必须完成输入类型(包名+类名)
Class对象的主要作用
通过Class对象,我们可以"解剖一个类"
- 创建对象:即使不知道类名,也可以创建
- 查看类信息:包括类名,包名,父类信息,接口等等
- 获取所有方法和字段:甚至包括私有方法
- **调用方法:**包括私有方法
- 动态操作字段值
Class对象获取构造函数方法
获取构造函数方法
-
Constructor<?>[] getConstructors()
:获取所有public构造函数方法java//获取类的所有public构造函数 Constructor<?>[] constructors = stuClass.getConstructors();
-
Constructor<?>[] getDeclaredConstructors()
:获取所有的构造函数包括privatejava//获取类所有的构造函数包括private Constructor<?>[] declaredConstructors = stuClass.getDeclaredConstructors();
-
Constructor<T> getConstructor(Class<?>... paramTypes)
:获取无参或有参构造函数的java//获取无参构造函数public Constructor<Student> classConstructor = stuClass.getConstructor();
-
Constructor<T> getDeclaredConstructor(Class<?>... paramTypes)
:获取任意访问权限的构造函数java//获取有参构造函数private,需传入参数类型的Class对象 Constructor<Student> declaredConstructor = stuClass.getDeclaredConstructor(Integer.class); declaredConstructor.setAccessible(true);//将访问权限置为true
通过构造函数创建对象的方法
-
T newInstance(Object... args)
- 使用构造函数创建实例:
java//无参构造函数创建对象 Constructor<Student> constructor = Student.class.getConstructor(); Student student = constructor.newInstance(); //有参构造函数创建对象 Constructor<Student> constructor1 = Student.class.getConstructor(String.class, Integer.class); Student student1 = constructor1.newInstance("张三",18);
字段操作
-
获取字段
-
Field[] getFields()
:获取所有public字段,包括父类java//获取所有public字段 Field[] fields = Student.class.getFields();
-
Field[] getDeclaredFields()
:获取本类所有字段,包括privatejava//获取本类所有字段包括private字段 Field[] declaredFields = Student.class.getDeclaredFields();
-
Field getField(String name)
:获取指定名称的public字段java//获取指定名称的public字段 Field name = Student.class.getField("name");
-
Field getDeclaredField(String name)
:获取任意访问权限的字段java//获取任意访问权限的字段 Field age = Student.class.getDeclaredField("age");
-
-
操作字段值
-
Object get(Object obj)
:获取字段值javaField age = Student.class.getDeclaredField("age"); age.setAccessible(true); Integer num = (Integer) age.get(student);
-
void set(Object obj,Object value
:修改字段值javaStudent student = new Student(); Field nameField = Student.class.getDeclaredField("name"); nameField.setAccessible(true);//突破访问权限 nameField.set(student, "zhangsan");
-
方法操作
-
获取方法
-
Method[] getMethods()
:获取所有public方法java//获取所有public方法包括父类 Method[] methods = Student.class.getMethods();
-
Method[] getDeclaredMethods()
:获取所有方法包括privatejava//获取所有private方法 Method[] declaredMethods = Student.class.getDeclaredMethods();
-
Method[] getMethod(String name,Class<?>... paramTypes)
获取指定参数的public方法java//获取指定参数的public方法 Method setName = Student.class.getMethod("setName", String.class); Method setAge = Student.class.getMethod("setAge", Integer.class);
-
Method[] getDeclaredMethod(String name,Class<?>... paramTypes)
java//获取任意访问权限的方法 Method getName = Student.class.getDeclaredMethod("getName"); getName.setAccessible(true);
-
-
调用方法
-
Object invoke(Object obj, Object... args)
:调用方法javaStudent student = new Student(); Method getName = Student.class.getDeclaredMethod("getName"); String name = (String) getName.invoke(student);
-
案例理解
封装一个通用方法,支持传入各种的对象类型都可以实现对应方法
java
/*
* @description:封装一个通用方法,支持传入各种的对象类型都可以实现对应方法
* @author: HYJ
* @date: 2025/2/17 10:25
* @param: [className, methodName]
* @return: void
**/
public static void invoke(String className, String methodName) {
try {
//获取Class对象
Class<?> clazz = Class.forName(className);
//获取构造器
Constructor<?> constructor = clazz.getConstructor();
//实例化对象
Object instance = constructor.newInstance();
//获取方法
Method method = clazz.getMethod(methodName);
//调用method的invoke执行方法
method.invoke(instance);
} catch (Exception e) {
e.printStackTrace();
}
}