前言
Java反射机制是Java语言提供的一种强大功能,允许在运行时动态检查和操作类的结构。与传统编程方式不同,反射使得程序能够在编译期不确定类型和方法的情况下,对类的构造函数、方法、字段等进行操作。这种灵活性在许多高级编程场景中至关重要,尤其是在框架开发、动态代理、依赖注入、测试工具和序列化等领域。通过反射,开发者可以编写出更加通用、灵活的代码,使应用程序具备更强的动态特性。然而,反射的使用也带来了性能开销和安全性挑战,因此需要在特定场景中慎重考虑。本文将详细探讨Java反射机制的原理、应用场景以及使用中的注意事项,帮助开发者更好地理解和应用这一强大的工具
问题:如果仅仅知道一个类的类名,能否动态得到类的定义信息,包括哪些方法, 属性等?
Java反射的概念
在运行状态中,在仅知道一个类名时,就可以动态获得类中的信息,创建对象,调用对象成员的机制成为Java反射机制
Java反射的作用
动态获取类的信息
Java反射主要包括
- Class 类型
- Constructor 构造方法
- Method 方法
- Field 属性
Class类型-->获取类的Class对象
第一种:类的途径获取
String classname = "com.kid.javaReflect.User";
Class clazz = Class.forName(classname);
第二种:类名获取
Class clazz2 = User.class; //直接User类获取
第三种:类对象获取
User user = new User();
Class clazz3 = user.getClass();
获取构造方法
1.获取类的Class对象
//使用反射机制时,只知道类的名称
String classname = "com.kid.javaReflect.User";
//1.通过类名,获得到类的Class对象
Class cla = Class.forName(classname);
2.通过类的Class对象获取构造方法
//获得类中的无参构造方法
Constructor constructor1 = cla.getConstructor();
//获得类中的有参构造方法
Constructor constructor2 = cla.getConstructor(String.class, String.class);
3.创建对象(使用构造方法创建对象)
//获得类中的构造方法,通过构造方法api中的方法创建对象
Constructor constructor1 = cla.getConstructor();
//创建对象
Object object1 = constructor1.newInstance();
//创建有参构造方法
Constructor constructor2 = cla.getConstructor(String.class, String.class);
//创建有对象
Object object2 = constructor1.newInstance("admin", "111");
4.获取私有的构造方法(可以获取所有类型的构造方法)
//虽然可以获取私有的构造方法,但是一般不建议操作私有成员,因为打破了封装性
cla.getDeclaredConstructor(); //获取类中任意的构造方法,包含私有的
cla.getDeclaredConstructors(); //获取类中所有的构造方法,包含私有的
Method 方法
Method getMethod(String name, Class... parameterTypes) : 通过指定方法名,参数类型,返回一个Method实例
Method类将类中的方法进行封装,可以动态获得方法的信息
例如 :
- getName:获得方法名字
- getParameterTypes:获得方法参数类型
除了动态获得方法信息外,Method还能动态调用某一个对象的具体方法
● invoke(Object obj, Object... args) :使用obj调用该方法,参数为args
代码演示:
获取类中的所有方法
Class clazz = MyClass.class;
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println("方法名:" + method.getName());
}
调用获取到的方法
Class clazz = MyClass.class;
Object obj = clazz.newInstance();
try {
Method method = clazz.getDeclaredMethod("privateMethod", int.class);
method.setAccessible(true);
method.invoke(obj, 10);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
e.printStackTrace();
}
Field 属性
获得Field实例,都是通过Class中的方法实现
● public Field getField(String name)通过指定Field名字,返回 Field实例.
Field类将类的属性进行封装,可以获得属性的基本信息、属性的值,也 可以对属性进行赋值.
- getName:返回属性的名字
- set:设置属性值
代码演示:
//使用反射机制时,只知道类的名称
String classname = "com.kid.javaReflect.User";
//1.通过类名,获得到类的Class对象
Class cla = Class.forName(classname);
//2.通过类的Class对象,创建对象
Object object = cla.newInstance();
获得类中的成员变量
//获得类中的成员变量
//cla.getField("account"); //获得指定名称的公共的成员变量
Field accountFiled = cla.getDeclaredField("account"); //获得指定名称的成员变量,包含私有的
cla.getField("account")--->拿去公共的变量
cla.getDeclaredField("account") ----> 拿去所有的,包括可以获取私有的成员变量
注:但是拿去私有的成员变量不可以赋值,等操作(因为破坏了封装性),也可以使用代码修改设置
field.setAccessible(true); //允许访问操作私有属性
模拟MyBatis反射:
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
/*
* Java中创建对象的方式
* 1.new
* 2.反序列化
* 3.反射机制
* 4.对象克隆
* */
//使用反射机制时,只知道类的名称
String classname = "com.kid.javaReflect.User";
//1.通过类名,获得到类的Class对象
Class cla = Class.forName(classname);
//2.通过类的Class对象,创建对象
Object object = cla.newInstance();
//获得类中的成员变量
//cla.getField("account"); //获得指定名称的公共的成员变量
Field accountFiled = cla.getDeclaredField("account"); //获得指定名称的成员变量,包含私有的
//accountFiled.set(object,"admin"); 这样会报错,因为不可以拿去私有属性操作
HashMap<String,String> map = new HashMap<>();
map.put("account","admin");
map.put("passWord","111");
Field[] declaredFields = cla.getDeclaredFields();
for (Field field : declaredFields){
field.setAccessible(true); //允许访问操作私有属性
field.set(object,map.get(field.getName()));
}
System.out.println(object);
}
Json简单实现
package com.kid.javaReflect;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class JsonUtil {
public static String objectToJson(Object object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class cla = object.getClass();
Field[] declaredFields = cla.getDeclaredFields();
String a = "";
for (Field field : declaredFields){
String getMethodName = "get" + field.getName().substring(0,1).toUpperCase()+field.getName().substring(1);
Method getMethod = cla.getMethod(getMethodName);
Object value = getMethod.invoke(object);
a = a + field.getName() + ":" + String.valueOf(value) +" ";
}
return a;
}
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User("admin","111");
System.out.println(objectToJson(user));
}
}
反射机制的使用场景
- 动态加载和调用:根据类名或方法名在运行时加载类、调用方法、访问字段。
- 框架实现:用于依赖注入(如Spring)、ORM(如Hibernate)等框架中,提供动态配置和操作。
- 动态代理:创建代理对象并处理方法调用,常用于AOP编程。
- 通用代码:操作未知类型的对象,编写更灵活的代码。
- 测试框架:自动发现和调用测试方法,访问私有成员。
- 处理注解:读取和处理注解,实现框架中的注解驱动逻辑
感谢大家的观看,本次分享就到这里。希望我的内容能够对您有所帮助。创作不易,欢迎大家多多支持,您的每一个点赞都是我持续更新的最大动力!如有不同意见,欢迎在评论区积极讨论,让我们一起学习、共同进步!如果有相关问题,也可以私信我,我会认真查看每一条留言。期待下次再见!
希望路飞的笑容可以治愈努力路途中的你我!
博主vx:Dreamkid05 --->欢迎大家和博主讨论问题