目录
- [🟠 29 反射机制](#🟠 29 反射机制)
-
- 一、什么是反射
-
- [1.1 反射的核心能力](#1.1 反射的核心能力)
- [1.2 反射的优缺点](#1.2 反射的优缺点)
- 二、Class类详解
-
- [2.1 获取Class对象的三种方式](#2.1 获取Class对象的三种方式)
- [2.2 Class类的常用方法](#2.2 Class类的常用方法)
- [2.3 基本类型与数组的Class对象](#2.3 基本类型与数组的Class对象)
- 三、获取构造方法
-
- [3.1 获取和使用构造方法](#3.1 获取和使用构造方法)
- [3.2 构造方法API速查](#3.2 构造方法API速查)
- 四、获取并调用方法
-
- [4.1 获取和调用普通方法](#4.1 获取和调用普通方法)
- [4.2 获取方法列表的对比](#4.2 获取方法列表的对比)
- 五、获取并操作字段
-
- [5.1 读写对象字段](#5.1 读写对象字段)
- [5.2 通过反射修改final字段(高级技巧)](#5.2 通过反射修改final字段(高级技巧))
- 六、动态代理
-
- [6.1 JDK动态代理](#6.1 JDK动态代理)
- [6.2 CGLIB动态代理](#6.2 CGLIB动态代理)
- [6.3 JDK代理 vs CGLIB代理](#6.3 JDK代理 vs CGLIB代理)
- 七、反射的性能与最佳实践
-
- [7.1 性能对比测试](#7.1 性能对比测试)
- [7.2 性能优化建议](#7.2 性能优化建议)
- 八、反射的应用场景
-
- [8.1 框架中的反射应用](#8.1 框架中的反射应用)
- [8.2 自定义简易IoC容器](#8.2 自定义简易IoC容器)
- 九、总结与互动
🟠 29 反射机制
更新日期:2026年6月 | Java入门到精通系列 第四阶段
© 版权声明:本文为原创技术文章,转载请联系作者并注明出处。
一、什么是反射
反射(Reflection) 是 Java 语言的一项强大特性,允许程序在运行时获取类的信息并操作类的属性和方法。简单来说,反射让我们能够"透视"一个类的内部结构。
1.1 反射的核心能力
| 能力 | 说明 | 示例 |
|---|---|---|
| 获取类信息 | 获取类名、父类、接口等 | Class.forName("java.lang.String") |
| 创建对象 | 动态实例化对象 | clazz.getDeclaredConstructor().newInstance() |
| 调用方法 | 动态调用任意方法 | method.invoke(obj, args) |
| 访问字段 | 读写私有字段 | field.set(obj, value) |
| 操作数组 | 动态创建和操作数组 | Array.newInstance(componentType, length) |
1.2 反射的优缺点
✅ 优点: ❌ 缺点:
├── 灵活性极高,运行时动态操作 ├── 性能开销较大
├── 框架基石(Spring、MyBatis等) ├── 破坏封装性
├── 支持泛型擦除后的类型恢复 ├── 编译期无法类型检查
└── 实现通用工具和插件机制 └── 代码可读性降低
二、Class类详解
java.lang.Class 是反射的入口,每个类在JVM中都有且仅有一个对应的 Class 对象。
2.1 获取Class对象的三种方式
java
public class ClassDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 方式1:通过类名.class(编译时确定)
Class<String> clazz1 = String.class;
System.out.println(clazz1); // class java.lang.String
// 方式2:通过对象.getClass()(运行时获取)
String str = "Hello";
Class<? extends String> clazz2 = str.getClass();
System.out.println(clazz2); // class java.lang.String
// 方式3:通过全限定类名(最灵活,常用于配置文件)
Class<?> clazz3 = Class.forName("java.lang.String");
System.out.println(clazz3); // class java.lang.String
// 三种方式获取的是同一个Class对象
System.out.println(clazz1 == clazz2); // true
System.out.println(clazz2 == clazz3); // true
}
}
2.2 Class类的常用方法
java
public class ClassInfoDemo {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java.util.ArrayList");
// 基本信息
System.out.println("类名: " + clazz.getName()); // java.util.ArrayList
System.out.println("简单类名: " + clazz.getSimpleName()); // ArrayList
System.out.println("包名: " + clazz.getPackageName()); // java.util
System.out.println("修饰符: " + Modifier.toString(clazz.getModifiers())); // public
// 继承关系
Class<?> superClass = clazz.getSuperclass();
System.out.println("父类: " + superClass.getName()); // java.util.AbstractList
// 实现的接口
Class<?>[] interfaces = clazz.getInterfaces();
System.out.println("实现接口:");
for (Class<?> iface : interfaces) {
System.out.println(" - " + iface.getName());
}
// 判断类型
System.out.println("是否是接口: " + clazz.isInterface()); // false
System.out.println("是否是数组: " + clazz.isArray()); // false
System.out.println("是否是枚举: " + clazz.isEnum()); // false
System.out.println("是否是注解: " + clazz.isAnnotation()); // false
System.out.println("是否是抽象类: " + Modifier.isAbstract(clazz.getModifiers())); // false
}
}
2.3 基本类型与数组的Class对象
java
public class PrimitiveClassDemo {
public static void main(String[] args) {
// 基本类型也有Class对象
Class<Integer> intClass = int.class;
Class<Void> voidClass = void.class;
System.out.println(intClass.isPrimitive()); // true
// 包装类
Class<Integer> wrapperClass = Integer.class;
System.out.println(wrapperClass.isPrimitive()); // false
// 数组的Class对象
Class<String[]> arrayClass = String[].class;
System.out.println(arrayClass.isArray()); // true
System.out.println(arrayClass.getComponentType()); // java.lang.String
// 动态创建数组
Object array = Array.newInstance(String.class, 5);
Array.set(array, 0, "Hello");
System.out.println(Array.get(array, 0)); // Hello
}
}
三、获取构造方法
3.1 获取和使用构造方法
java
import java.lang.reflect.Constructor;
// 用于演示的类
class Student {
private String name;
private int age;
public Student() { this.name = "Unknown"; this.age = 0; }
public Student(String name) { this.name = name; this.age = 0; }
private Student(String name, int age) { this.name = name; this.age = age; }
@Override
public String toString() {
return "Student{name='" + name + "', age=" + age + "}";
}
}
public class ConstructorDemo {
public static void main(String[] args) throws Exception {
Class<Student> clazz = Student.class;
// 获取所有public构造方法
Constructor<?>[] publicConstructors = clazz.getConstructors();
System.out.println("public构造方法数量: " + publicConstructors.length);
// 获取所有构造方法(包括private)
Constructor<?>[] allConstructors = clazz.getDeclaredConstructors();
System.out.println("所有构造方法数量: " + allConstructors.length);
for (Constructor<?> c : allConstructors) {
System.out.println(" " + Modifier.toString(c.getModifiers()) + " " + c);
}
// 使用无参构造创建对象
Constructor<Student> noArgConstructor = clazz.getConstructor();
Student s1 = noArgConstructor.newInstance();
System.out.println(s1); // Student{name='Unknown', age=0}
// 使用带参构造创建对象
Constructor<Student> oneArgConstructor = clazz.getConstructor(String.class);
Student s2 = oneArgConstructor.newInstance("张三");
System.out.println(s2); // Student{name='张三', age=0}
// 使用private构造方法(需要setAccessible)
Constructor<Student> privateConstructor = clazz.getDeclaredConstructor(String.class, int.class);
privateConstructor.setAccessible(true); // 暴力反射
Student s3 = privateConstructor.newInstance("李四", 25);
System.out.println(s3); // Student{name='李四', age=25}
}
}
3.2 构造方法API速查
| 方法 | 说明 |
|---|---|
getConstructor(Class<?>... params) |
获取指定参数的public构造方法 |
getConstructors() |
获取所有public构造方法 |
getDeclaredConstructor(Class<?>... params) |
获取指定参数的任意构造方法 |
getDeclaredConstructors() |
获取所有构造方法(含private) |
newInstance(Object... args) |
使用该构造方法创建实例 |
setAccessible(true) |
突破private访问限制 |
四、获取并调用方法
4.1 获取和调用普通方法
java
import java.lang.reflect.Method;
class Calculator {
public int add(int a, int b) { return a + b; }
public int multiply(int a, int b) { return a * b; }
private String secret() { return "这是私有方法"; }
public static void greet(String name) { System.out.println("Hello, " + name + "!"); }
}
public class MethodDemo {
public static void main(String[] args) throws Exception {
Class<Calculator> clazz = Calculator.class;
Calculator calc = clazz.getDeclaredConstructor().newInstance();
// 获取并调用add方法
Method addMethod = clazz.getMethod("add", int.class, int.class);
Object result = addMethod.invoke(calc, 10, 20);
System.out.println("10 + 20 = " + result); // 10 + 20 = 30
// 获取并调用multiply方法
Method multiplyMethod = clazz.getMethod("multiply", int.class, int.class);
System.out.println("5 * 6 = " + multiplyMethod.invoke(calc, 5, 6)); // 5 * 6 = 30
// 调用私有方法
Method secretMethod = clazz.getDeclaredMethod("secret");
secretMethod.setAccessible(true);
String secret = (String) secretMethod.invoke(calc);
System.out.println(secret); // 这是私有方法
// 调用静态方法(第一个参数传null)
Method greetMethod = clazz.getMethod("greet", String.class);
greetMethod.invoke(null, "World"); // Hello, World!
// 获取方法信息
System.out.println("返回类型: " + addMethod.getReturnType().getName()); // int
System.out.println("参数个数: " + addMethod.getParameterCount()); // 2
Class<?>[] paramTypes = addMethod.getParameterTypes();
for (Class<?> type : paramTypes) {
System.out.println("参数类型: " + type.getName());
}
}
}
4.2 获取方法列表的对比
| 方法 | 区别 |
|---|---|
getMethod(name, params) |
获取public方法(含继承的) |
getMethods() |
获取所有public方法(含继承的) |
getDeclaredMethod(name, params) |
获取本类声明的方法(不含继承) |
getDeclaredMethods() |
获取本类声明的所有方法(含private) |
五、获取并操作字段
5.1 读写对象字段
java
import java.lang.reflect.Field;
class Person {
public String name;
private int age;
protected String address;
private static String country = "China";
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + ", address='" + address + "'}";
}
}
public class FieldDemo {
public static void main(String[] args) throws Exception {
Class<Person> clazz = Person.class;
Person person = new Person("张三", 25, "北京");
// 读取public字段
Field nameField = clazz.getField("name");
System.out.println("name: " + nameField.get(person)); // 张三
// 修改public字段
nameField.set(person, "李四");
System.out.println("修改后: " + person);
// 读写private字段
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true);
System.out.println("age: " + ageField.getInt(person)); // 25
ageField.set(person, 30);
System.out.println("修改后age: " + ageField.getInt(person)); // 30
// 读写静态字段
Field countryField = clazz.getDeclaredField("country");
countryField.setAccessible(true);
System.out.println("country: " + countryField.get(null)); // China
countryField.set(null, "中国");
System.out.println("修改后country: " + countryField.get(null)); // 中国
// 遍历所有字段
System.out.println("\n所有字段信息:");
Field[] allFields = clazz.getDeclaredFields();
for (Field f : allFields) {
f.setAccessible(true);
System.out.printf(" %s %s = %s%n",
Modifier.toString(f.getModifiers()),
f.getType().getSimpleName(),
f.getName());
}
}
}
5.2 通过反射修改final字段(高级技巧)
java
public class FinalFieldDemo {
public static void main(String[] args) throws Exception {
// 修改static final字段(Java 12+需要特殊处理)
Field field = Person.class.getDeclaredField("country");
field.setAccessible(true);
// Java 12+ 中需要移除final修饰符
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, "日本");
System.out.println(field.get(null)); // 日本
System.out.println("⚠️ 注意:修改final字段是危险操作,仅用于了解机制");
}
}
六、动态代理
动态代理是反射最经典的应用之一,Spring AOP的核心实现原理。
6.1 JDK动态代理
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 接口
interface UserService {
void addUser(String name);
void deleteUser(String name);
String findUser(String name);
}
// 实现类
class UserServiceImpl implements UserService {
@Override
public void addUser(String name) { System.out.println("添加用户: " + name); }
@Override
public void deleteUser(String name) { System.out.println("删除用户: " + name); }
@Override
public String findUser(String name) { return "用户[" + name + "]"; }
}
// 通用的InvocationHandler实现
class LoggingHandler implements InvocationHandler {
private final Object target;
public LoggingHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("📋 [日志] 调用方法: " + method.getName());
System.out.println("📋 [日志] 参数: " + (args != null ? Arrays.toString(args) : "无"));
long start = System.currentTimeMillis();
Object result = method.invoke(target, args); // 调用真实方法
long cost = System.currentTimeMillis() - start;
System.out.println("📋 [日志] 返回值: " + result);
System.out.println("📋 [日志] 耗时: " + cost + "ms");
return result;
}
}
public class JdkProxyDemo {
public static void main(String[] args) {
// 创建代理对象
UserService realService = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new LoggingHandler(realService)
);
// 通过代理调用方法
proxy.addUser("张三");
System.out.println("---");
String user = proxy.findUser("李四");
System.out.println("查询结果: " + user);
}
}
输出结果:
📋 [日志] 调用方法: addUser
📋 [日志] 参数: [张三]
添加用户: 张三
📋 [日志] 返回值: null
📋 [日志] 耗时: 0ms
---
📋 [日志] 调用方法: findUser
📋 [日志] 参数: [李四]
📋 [日志] 返回值: 用户[李四]
📋 [日志] 耗时: 0ms
查询结果: 用户[李四]
6.2 CGLIB动态代理
java
// CGLIB代理不需要接口,可以代理普通类
// 需要引入cglib依赖
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
class OrderService {
public String createOrder(String product) {
return "订单已创建: " + product;
}
}
class CglibInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
System.out.println("[CGLIB] 前置处理");
Object result = methodProxy.invokeSuper(obj, args);
System.out.println("[CGLIB] 后置处理");
return result;
}
}
public class CglibProxyDemo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OrderService.class);
enhancer.setCallback(new CglibInterceptor());
OrderService proxy = (OrderService) enhancer.create();
System.out.println(proxy.createOrder("iPhone"));
}
}
6.3 JDK代理 vs CGLIB代理
| 特性 | JDK动态代理 | CGLIB代理 |
|---|---|---|
| 实现方式 | 基于接口 | 基于继承 |
| 要求 | 目标类必须实现接口 | 目标类不能是final |
| 性能 | 创建快,调用稍慢 | 创建慢,调用快 |
| Spring默认 | 有接口时使用 | 无接口时使用 |
| 代理原理 | Proxy.newProxyInstance() |
Enhancer.create() |
七、反射的性能与最佳实践
7.1 性能对比测试
java
public class ReflectionBenchmark {
public static void main(String[] args) throws Exception {
Student student = new Student("测试", 20);
Class<Student> clazz = Student.class;
// 直接调用
long start = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
student.toString();
}
long directTime = System.nanoTime() - start;
// 反射调用(每次获取Method)
Method method = clazz.getMethod("toString");
start = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
method.invoke(student);
}
long reflectTime = System.nanoTime() - start;
// 反射调用(关闭安全检查)
method.setAccessible(true);
start = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
method.invoke(student);
}
long fastReflectTime = System.nanoTime() - start;
System.out.println("直接调用: " + directTime / 1_000_000 + "ms");
System.out.println("反射调用: " + reflectTime / 1_000_000 + "ms");
System.out.println("优化反射: " + fastReflectTime / 1_000_000 + "ms");
}
}
7.2 性能优化建议
| 策略 | 说明 |
|---|---|
| 缓存Method/Field对象 | 避免重复查找 |
调用setAccessible(true) |
跳过安全检查,提升性能 |
| 使用MethodHandle | Java 7+,接近直接调用的性能 |
| 考虑代码生成 | 如ASM、ByteBuddy |
八、反射的应用场景
8.1 框架中的反射应用
| 框架/场景 | 反射用途 |
|---|---|
| Spring IoC | 根据配置文件创建Bean实例 |
| Spring AOP | 动态代理实现切面编程 |
| MyBatis | 将ResultSet映射到POJO |
| JUnit | 发现并调用@Test标注的方法 |
| 序列化框架 | Jackson/Gson通过反射读写字段 |
| IDE | 代码提示、自动补全 |
8.2 自定义简易IoC容器
java
import java.util.HashMap;
import java.util.Map;
// 简易IoC容器
class SimpleContainer {
private Map<Class<?>, Object> beans = new HashMap<>();
// 注册Bean
public <T> void register(Class<T> clazz) throws Exception {
Constructor<T> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
T instance = constructor.newInstance();
// 自动注入:遍历字段,查找@Autowired注解
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(MyAutowired.class)) {
Object dependency = beans.get(field.getType());
if (dependency != null) {
field.setAccessible(true);
field.set(instance, dependency);
}
}
}
beans.put(clazz, instance);
}
// 获取Bean
@SuppressWarnings("unchecked")
public <T> T getBean(Class<T> clazz) {
return (T) beans.get(clazz);
}
}
// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface MyAutowired {}
// 使用示例
class UserRepository {
public String findUser() { return "张三"; }
}
class UserService {
@MyAutowired
private UserRepository userRepository;
public String getUser() {
return userRepository.findUser();
}
}
public class IoCDemo {
public static void main(String[] args) throws Exception {
SimpleContainer container = new SimpleContainer();
container.register(UserRepository.class);
container.register(UserService.class);
UserService service = container.getBean(UserService.class);
System.out.println(service.getUser()); // 张三
}
}
九、总结与互动
核心知识点回顾
📌 反射机制核心要点:
├── Class类是反射的入口,有三种获取方式
├── getDeclaredXxx() 获取本类声明的(含private)
├── getXxx() 获取public的(含继承的)
├── setAccessible(true) 突破private限制
├── 动态代理是反射最重要的应用之一
└── 反射性能较低,应缓存Method/Field对象
思考题 🤔
- 为什么说反射是框架的基石? 没有反射,Spring会变成什么样?
- JDK动态代理为什么只能代理接口? 如果要代理类该怎么做?
Class.forName()和ClassLoader.loadClass()有什么区别?
下篇预告 👉
下一篇:30-注解与元编程 ------ 深入学习Java注解的定义、处理和元编程技巧,理解Spring框架是如何通过注解驱动的!