反射
- 什么是反射?
- 反射相关的类⭐
- Class⭐
-
- [.class 文件与 Class 对象的映射关系表](#.class 文件与 Class 对象的映射关系表)
- [Class: 常用获得类相关的方法](#Class: 常用获得类相关的方法)
- Field:常用获得类中属性相关的方法⭐
- Constructor:获得类中构造方法相关的方法
- Method:获得类中方法相关的方法
- 获得类中注解相关的方法
- 反射相关面试笔试题
什么是反射?
反射是Java提供的一种机制,允许程序在运行时动态地获取类的完整信息,包括:
- 类的构造方法、成员变量、成员方法
- 类的修饰符、父类、实现的接口
- 类上的注解信息
反射相关的类⭐
反射的主要功能集中在java.lang.reflect包中,包括Constructor、Method、Field三个核心类。
| 类名 | 用途简述 |
|---|---|
Class |
代表类的实体,存储着类的完整结构信息(类名、包、字段、方法、构造器等),是反射操作的入口。 |
Constructor |
代表类的构造方法。用于在运行时动态创建对象实例,支持调用带参数或私有的构造器。 |
Method |
代表类的成员方法。用于在运行时动态调用指定对象的方法,包括私有方法。 |
Field |
代表类的成员变量(属性)。用于在运行时动态获取或修改对象中的字段值,即使是私有的也可以。 |
使用层级关系图

Class⭐
.class 文件与 Class 对象的映射关系表
.class 文件 → JVM 类加载 → Class 对象实例化 的底层逻辑链条。
| 阶段 | 形态 | 位置 | 核心产物 | 反射的意义 |
|---|---|---|---|---|
| 1. 编译期 | YourClass.java |
硬盘(源码) | YourClass.class(字节码指令集) |
静态定义,类结构被固化为二进制流 |
| 2. 类加载期 | 字节码二进制流 | JVM 方法区(元空间) | java.lang.Class 对象实例 |
将静态文件激活为运行时可操作的内存对象 |
| 3. 运行期 | Class 对象 + 堆内实例 |
JVM 堆内存 | Field、Method、Constructor 镜像 |
获得动态改变类属性/动作的能力 |
Class: 常用获得类相关的方法
| 方法 | 用途 |
|---|---|
getClassLoader() |
获得类的加载器 |
getDeclaredClasses() |
返回一个数组,数组中包含该类中所有类和接口类的对象(包括私有) |
forName(String className) |
根据类名返回类的对象 |
newInstance() |
创建类的实例 |
getName() |
获得类的完整路径名字 |
java
// 获取Class对象的三种方式
// 获取Class对象
Class<?> clazz = YourClass.class;
// 通过对象获取Class对象
YourClass obj = new YourClass();
Class<?> clazz = obj.getClass();
//通过Class.forName()动态加载
Class<?> clazz = Class.forName("com.example.YourClass");
// 获取类加载器
ClassLoader classLoader = clazz.getClassLoader();
// 获取所有声明的类和接口
Class<?>[] declaredClasses = clazz.getDeclaredClasses();
// 创建实例
Object instance = clazz.newInstance(); // Java 9+ 已弃用
Object instance = clazz.getDeclaredConstructor().newInstance();
// 获取类名
String className = clazz.getName();
Field:常用获得类中属性相关的方法⭐
| 方法 | 用途 |
|---|---|
getField(String name) |
获得某个公有的属性对象 |
getFields() |
获得所有公有的属性对象 |
getDeclaredField(String name) |
获得某个属性对象 |
getDeclaredFields() |
获得所有属性对象 |
java
// 获取公有属性
Field publicField = clazz.getField("publicFieldName");
// 获取所有公有属性
Field[] publicFields = clazz.getFields();
// 获取声明属性(包括私有)
Field declaredField = clazz.getDeclaredField("privateFieldName");
// 获取所有声明属性
Field[] declaredFields = clazz.getDeclaredFields();
// 设置可访问性(用于私有属性)
declaredField.setAccessible(true);
Constructor:获得类中构造方法相关的方法
| 方法 | 用途 |
|---|---|
getConstructor(Class...<?> parameterTypes) |
获得该类中与参数类型匹配的公有构造方法 |
getConstructors() |
获得该类的所有公有构造方法 |
getDeclaredConstructor(Class...<?> parameterTypes) |
获得该类中与参数类型匹配的构造方法 |
getDeclaredConstructors() |
获得该类所有构造方法 |
java
// 获取公有构造方法
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
// 获取所有公有构造方法
Constructor<?>[] constructors = clazz.getConstructors();
// 获取声明构造方法(包括私有)
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();
// 获取所有构造方法
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
// 创建实例
Object instance = constructor.newInstance("参数1", 123);
Method:获得类中方法相关的方法
| 方法 | 用途 |
|---|---|
getMethod(String name, Class...<?> parameterTypes) |
获得该类某个公有的方法 |
getMethods() |
获得该类所有公有的方法 |
getDeclaredMethod(String name, Class...<?> parameterTypes) |
获得该类某个方法 |
getDeclaredMethods() |
获得该类所有方法 |
java
// 获取公有方法
Method method = clazz.getMethod("publicMethodName", String.class, int.class);
// 获取所有公有方法
Method[] methods = clazz.getMethods();
// 获取声明方法(包括私有)
Method declaredMethod = clazz.getDeclaredMethod("privateMethodName");
// 获取所有方法
Method[] declaredMethods = clazz.getDeclaredMethods();
// 调用方法
method.invoke(instance, "参数1", 456);
获得类中注解相关的方法
| 方法 | 用途 |
|---|---|
getAnnotation(Class<T> annotationClass) |
返回该类上与参数类型匹配的公有注解对象 |
getAnnotations() |
返回该类上所有的公有注解对象 |
getDeclaredAnnotation(Class<T> annotationClass) |
返回该类上与参数类型匹配的所有注解对象 |
getDeclaredAnnotations() |
返回该类上所有的注解对象 |
java
// 获取特定类型的公有注解
Annotation annotation = clazz.getAnnotation(MyAnnotation.class);
// 获取所有公有注解
Annotation[] annotations = clazz.getAnnotations();
// 获取特定类型的所有注解(包括私有)
Annotation declaredAnnotation = clazz.getDeclaredAnnotation(MyAnnotation.class);
// 获取所有注解(包括私有)
Annotation[] declaredAnnotations = clazz.getDeclaredAnnotations();
速记口诀:
- 带
Declared→ 全都要(包括私有成员,但只限于当前类声明,不含继承)- 不带
Declared→ 只要公有(包括从父类/接口继承而来的公有成员)
反射相关面试笔试题
反射的优缺点是什么?⭐
优点:灵活性强,可扩展性好,适用于框架开发
缺点:性能较低,安全性差,破坏封装性
如何通过反射创建对象?⭐
java
Class<?> clazz = Class.forName("com.example.YourClass");
Object obj = clazz.getDeclaredConstructor().newInstance();

如何通过反射调用私有方法?⭐
java
Class<?> clazz = Class.forName("com.example.YourClass");
Object obj = clazz.getDeclaredConstructor().newInstance();
Method method = clazz.getDeclaredMethod("privateMethod");
method.setAccessible(true);
method.invoke(obj);

如何通过反射访问私有字段?⭐
java
Class<?> clazz = Class.forName("com.example.YourClass");
Object obj = clazz.getDeclaredConstructor().newInstance();
Field field = clazz.getDeclaredField("privateField");
field.setAccessible(true);
Object value = field.get(obj);
field.set(obj, newValue);

反射与new的区别是什么?
- new在编译时确定类型,反射在运行时确定类型
- 通过 new 创建对象效率更高。
原因:反射时需要先查找类资源、通过类加载器加载、进行访问安全检查,过程繁琐,所以效率较低
反射如何处理泛型?
- 使用
getGenericReturnType()等方法获取泛型信息- 需要处理Type类型
反射在Spring框架中的应用?
- IOC容器通过反射创建和管理Bean
- AOP通过反射实现动态代理
编写一个方法,通过反射获取对象的所有字段名和值
java
public static void printFields(Object obj) throws Exception {
Class<?> clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
System.out.println(field.getName() + ": " + field.get(obj));
}
}
编写一个方法,通过反射调用对象的方法
java
public static Object invokeMethod(Object obj, String methodName, Object... args) throws Exception {
Class<?> clazz = obj.getClass();
Class<?>[] paramTypes = new Class<?>[args.length];
for (int i = 0; i < args.length; i++) {
paramTypes[i] = args[i].getClass();
}
Method method = clazz.getMethod(methodName, paramTypes);
return method.invoke(obj, args);
}