Java 反射机制详解
一、什么是反射
Java 反射(Reflection)是 Java 语言的动态机制:程序在运行阶段,可以获取任意类的完整结构信息(类名、构造方法、成员变量、成员方法、注解),并且能够实例化对象、调用成员方法、读写成员变量。
正常开发是new 类名()编译期创建对象(静态);反射在运行时通过 Class 对象反向操作类,属于动态编程,是 Spring、MyBatis 等主流框架的底层基石。
二、Class:反射的入口
所有类加载后,JVM 都会在堆中生成唯一的Class对象,存储这个类的全部元数据,反射全部从 Class 对象入手。
获取 Class 对象三种方式
java
运行
//1. 类名.class(编译期,不触发类加载)
Class<User> clazz1 = User.class;
//2. 对象.getClass()(已有实例对象时)
User user = new User();
Class<?> clazz2 = user.getClass();
//3. Class.forName("全限定类名")(最常用,运行时加载类,框架配置文件用)
Class<?> clazz3 = Class.forName("com.demo.User");
同一个类在 JVM 中只会生成一个 Class 实例,三种方式拿到的是同一个对象。
三、反射核心常用 API
java.lang.reflect包下提供构造器、字段、方法三大核心类:
- Constructor:操作构造方法,用来创建类实例
- Field:操作成员变量,实现取值 / 赋值
- Method:操作成员方法,运行时调用方法
1. 通过反射实例化对象
java
运行
//1.获取Class
Class<?> clazz = Class.forName("com.demo.User");
//2.获取无参构造器
Constructor<?> con = clazz.getDeclaredConstructor();
con.setAccessible(true);//突破私有构造权限
//3.创建对象
Object obj = con.newInstance();
2. 反射操作成员变量
java
运行
//获取私有成员变量name
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);//关闭权限校验,访问私有属性
field.set(obj,"张三");//给对象赋值
String name = (String) field.get(obj);//获取属性值
3. 反射调用成员方法
java
运行
//获取带参方法
Method method = clazz.getDeclaredMethod("setAge",Integer.class);
method.setAccessible(true);
method.invoke(obj,20);//执行方法,传入实参
getDeclaredXXX():获取所有(公有 + 私有)构造 / 字段 / 方法;getXXX()只获取 public 修饰的。
四、setAccessible (true) 作用
Java 封装性限制不能直接访问私有成员,setAccessible(true)关闭 Java 语法权限检查,绕过 private 保护,是反射访问私有属性 / 方法的关键。
注意:仅运行时生效,不会修改源码权限。
五、反射优缺点
优点
- 动态灵活:运行时动态创建对象、调用方法,不用提前硬编码
new,框架配置化开发的基础。 - 解耦:比如 Spring IoC 容器通过配置 XML / 注解,反射实例化 Bean,不用在代码写死对象创建。
- 通用工具开发:ORM 框架 MyBatis 通过反射映射数据库字段和实体类属性。
缺点
- 性能损耗:绕开编译期优化,相比直接 new、直接调用方法,反射执行速度慢。
- 破坏封装:暴力访问私有变量、私有方法,违背面向对象封装原则。
- 安全性隐患:非法代码利用反射绕过权限修改私有数据。
六、实际应用场景
- Spring 框架 IOC:读取配置类 / XML 中的类全类名,反射创建 Bean 对象,实现依赖注入。
- ORM 框架 MyBatis:查询数据库后,通过反射实例化实体类,把 ResultSet 字段映射到对象属性。
- 注解开发:运行时利用反射读取类、方法上自定义注解信息,实现自定义业务逻辑。
- 通用工具类:对象拷贝工具(BeanUtils),通过反射遍历两个类字段自动赋值。
七、总结
反射是 Java 动态编程的核心,牺牲少量性能换取超强灵活性,日常业务开发很少直接手写反射,但几乎所有主流框架底层都依赖反射实现。理解反射原理,是看懂 Spring 等框架源码的必备基础。
拓展:反射与类加载
Class.forName () 默认触发类的静态代码块执行,JDBC 早期加载数据库驱动Class.forName("com.mysql.cj.jdbc.Driver")就是利用反射加载驱动类,驱动类静态代码块自动注册驱动。
更多推荐




所有评论(0)