1. 反射概述
1.1 什么是反射
反射(Reflection)是 Java 提供的强大特性,允许程序在运行时动态地获取、访问类的所有信息(包括类名、属性、方法、构造器、注解等),并能动态操作这些信息,突破编译期的访问限制。
详细讲解了 Java 反射机制,涵盖 Class 类获取方式、Constructor 构造器操作、Field 成员变量操作、Method 方法调用以及 Annotation 注解解析。内容包含各类 API 说明、代码示例及实战练习题,帮助读者理解如何通过反射在运行时动态获取和操作类信息,突破编译期限制,是掌握 Spring 等框架底层原理的基础。

反射(Reflection)是 Java 提供的强大特性,允许程序在运行时动态地获取、访问类的所有信息(包括类名、属性、方法、构造器、注解等),并能动态操作这些信息,突破编译期的访问限制。
new 关键字,通过类名字符串构造任意类的对象;JVM 加载完类后,会在堆内存的方法区中生成一个 Class 类型的对象 —— 这个对象是该类的'说明书',包含了类的所有信息(类名、父类、接口、属性、方法、构造器等)。
核心特点:
Class 对象;Class 对象是反射的入口,所有反射操作都基于 Class 对象展开;Person 类,还是 JDK 内置的 String/ArrayList,加载后都会生成对应的 Class 对象。获取 Class 对象有三种核心方式,以下以 Student 类为例演示:
public class Student {
private String name;
private int age;
private String address;
// 构造方法:私有、默认、公共(多参)
public Student() {}
private Student(String name) { this.name = name; }
Student(String name, int age) { this.name = name; this.age = age; }
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
// 成员方法:私有、公共(无参/有参/有返回值)
private void function() {
System.out.println("执行 function()");
}
public void method1() {
System.out.println("执行 method1()");
}
public void method2(String s) {
System.out.println("执行 method2:" + s);
}
public String method3(String s, int i) {
return "执行 method3:" + s + "," + i;
}
@Override
public String toString() {
return "Student{" + "name='" + name + '\'' + ", age=" + age + ", address='" + address + '\'' + '}';
}
}
public class ClassTest {
public static void main(String[] args) throws ClassNotFoundException {
// 方式 1:类.class(编译期确定,最安全)
System.out.println("---------方式 1:类.class---------");
Class<Student> c1 = Student.class;
System.out.println(c1); // class com.hg.java.Student
Class<Student> c2 = Student.class;
System.out.println(c1 == c2); // true(同一 Class 对象)
// 方式 2:对象.getClass()(运行时获取,适用于已有对象的场景)
System.out.println("---方式 2:对象.getClass()---");
Student s = new Student();
Class<? extends Student> c3 = s.getClass();
System.out.println(c1 == c3); // true
// 方式 3:Class.forName(全类名)(动态加载,最灵活,适用于配置文件场景)
System.out.println("----方式 3:Class.forName(全类名)----");
Class<?> c4 = Class.forName("com.hg.java.Student");
System.out.println(c1 == c4); // true
}
}
java.lang.reflect.Constructor 是反射体系中描述类的构造器的类:
Constructor 对象;Constructor 对象可在运行时创建类的实例,甚至调用私有构造器。| 方法 | 说明 |
|---|---|
Constructor<?>[] getConstructors() | 返回所有公共构造方法的数组 |
Constructor<?>[] getDeclaredConstructors() | 返回所有构造方法的数组(含私有) |
Constructor getConstructor(Class<?>... parameterTypes) | 返回单个公共构造方法(指定参数类型) |
Constructor getDeclaredConstructor(Class<?>...parameterTypes) | 返回单个构造方法(含私有,指定参数类型) |
public class ConstructorTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class<?> c = Class.forName("com.hg.java1.Student");
// 1. 获取所有构造器(含私有)
System.out.println("---返回所有构造方法的数组----");
Constructor<?>[] cons = c.getDeclaredConstructors();
for (Constructor con : cons) {
System.out.println(con);
}
// 2. 获取单个公共构造器
System.out.println("-----返回单个构造方法----");
Constructor<?> con = c.getConstructor(); // 无参构造
System.out.println(con);
con = c.getConstructor(String.class, int.class, String.class); // 三参构造
System.out.println(con);
}
}
核心方法:T newInstance(Object...initargs) —— 根据指定构造器创建对象。
public class ConstructorTest {
public static void main(String[] args) throws Exception {
Class<?> c = Class.forName("com.hg.java1.Student");
// 1. 通过无参构造创建对象
System.out.println("------通过反射获取公共构造方法并创建对象--------");
Constructor<?> con = c.getConstructor();
Student s1 = (Student) con.newInstance();
System.out.println(s1); // Student{name='null', age=0, address='null'}
// 2. 通过三参构造创建对象
con = c.getConstructor(String.class, int.class, String.class);
Object obj = con.newInstance("林青霞", 30, "西安");
System.out.println(obj); // Student{name='林青霞', age=30, address='西安'}
}
}
java.lang.reflect.Field 是反射体系中描述类的成员变量的类:
Field 对象;Field 对象可在运行时读写变量值,突破访问权限限制。| 方法 | 说明 |
|---|---|
Field[] getFields() | 返回所有公共成员变量的数组 |
Field[] getDeclaredFields() | 返回所有成员变量的数组(含私有) |
Field getField(String name) | 返回单个公共成员变量(指定变量名) |
Field getDeclaredField(String name) | 返回单个成员变量(含私有,指定变量名) |
public class FieldTest {
public static void main(String[] args) throws Exception {
Class<?> c = Class.forName("com.hg.java1.Student");
// 1. 获取所有公共成员变量
System.out.println("---------返回所有公共成员变量的数组----------");
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field);
}
// 2. 获取所有成员变量(含私有)
System.out.println("---------返回所有成员变量的数组----------");
fields = c.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
// 3. 获取单个公共成员变量
System.out.println("---------返回单个公共成员变量----------");
Field addressField = c.getField("address");
System.out.println(addressField);
// 4. 获取单个私有成员变量
System.out.println("---------返回单个私有成员变量----------");
Field nameField = c.getDeclaredField("name");
System.out.println(nameField);
}
}
核心方法:void set(Object obj,Object value) —— 给指定对象的成员变量赋值。
public class FieldTest {
public static void main(String[] args) throws Exception {
Class<?> c = Class.forName("com.hg.java1.Student");
// 先通过构造器创建对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
// 1. 给公共变量 address 赋值
Field addressField = c.getField("address");
addressField.set(obj, "西安");
System.out.println(obj); // Student{name='null', age=0, address='西安'}
// 2. 给私有变量 age 赋值(默认禁止访问,需先解除限制)
Field ageField = c.getDeclaredField("age");
ageField.setAccessible(true); // 解除访问权限检查
ageField.set(obj, 30);
System.out.println(obj); // Student{name='null', age=30, address='西安'}
}
}
java.lang.reflect.Method 是反射体系中描述类的成员方法的类:
Method 对象;Method 对象可在运行时调用方法,包括私有方法。| 方法 | 说明 |
|---|---|
Method[] getMethods() | 返回所有公共成员方法的数组(含父类继承的) |
Method[] getDeclaredMethods() | 返回所有成员方法的数组(仅本类,含私有) |
Method getMethod(String name, Class<?>... parameterTypes) | 返回单个公共方法(指定方法名 + 参数类型) |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 返回单个方法(含私有,指定方法名 + 参数类型) |
public class MethodTest {
public static void main(String[] args) throws Exception {
Class<?> c = Class.forName("com.hg.java1.Student");
// 1. 获取所有公共方法(含 toString、equals 等父类方法)
System.out.println("-----------返回所有公共成员方法的数组--------");
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method);
}
// 2. 获取所有本类方法(含私有)
System.out.println("-----------返回所有成员方法的数组--------");
methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
// 3. 获取单个公共方法
System.out.println("-----------单个公共成员方法--------");
Method method = c.getMethod("method1"); // 无参
System.out.println(method);
Method method2 = c.getMethod("method2", String.class); // 单参
System.out.println(method2);
Method method3 = c.getMethod("method3", String.class, int.class); // 双参
System.out.println(method3);
// 4. 获取私有方法
System.out.println("-----------单个非公共成员方法--------");
Method method4 = c.getDeclaredMethod("function");
System.out.println(method4);
}
}
核心方法:Object invoke(Object obj,Object... args) —— 调用指定对象的方法,参数为 args,返回值为方法执行结果。
public class MethodTest {
public static void main(String[] args) throws Exception {
Class<?> c = Class.forName("com.hg.java1.Student");
// 创建对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
// 1. 调用无参公共方法
Method method = c.getMethod("method1");
method.invoke(obj);
// 2. 调用单参公共方法
Method method2 = c.getMethod("method2", String.class);
method2.invoke(obj, "林青霞");
// 3. 调用有返回值的公共方法
Method method3 = c.getMethod("method3", String.class, int.class);
Object o = method3.invoke(obj, "林青霞", 30);
System.out.println(o); // 执行 method3():林青霞,30
// 4. 调用私有方法(需解除访问限制)
Method method4 = c.getDeclaredMethod("function");
method4.setAccessible(true);
method4.invoke(obj);
}
}
java.lang.annotation.Annotation 是反射体系中描述注解的类:
Annotation 对象;@Retention(RetentionPolicy.RUNTIME),否则反射无法读取。| 方法 | 说明 |
|---|---|
Annotation[] getAnnotations() | 返回元素上的所有注解(含继承的) |
Annotation[] getDeclaredAnnotations() | 返回元素上的所有注解(仅本元素) |
Annotation getAnnotation(Class<?> annoClass) | 返回指定类型的注解(含继承的) |
Annotation getDeclaredAnnotation(Class<?> annoClass) | 返回指定类型的注解(仅本元素) |
isAnnotationPresent(Class<A> annoClass) | 判断元素是否被指定注解标记 |
import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.annotation.Annotation;
public class AnnotationTest {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.hg.java1.SampleClass");
// 1. 解析类上的注解
System.out.println("----------解析类上的注解---------");
if (clazz.isAnnotationPresent(CustomAnnotation.class)) {
CustomAnnotation customAnnotation = clazz.getAnnotation(CustomAnnotation.class);
System.out.println("类注解-name: " + customAnnotation.name());
System.out.println("类注解-value: " + customAnnotation.value());
}
// 2. 解析属性上的注解
System.out.println("----------解析属性上的注解---------");
Field field = clazz.getDeclaredField("sampleField");
if (field.isAnnotationPresent(CustomAnnotation.class)) {
CustomAnnotation customAnnotation = field.getAnnotation(CustomAnnotation.class);
System.out.println("属性注解-name: " + customAnnotation.name());
System.out.println("属性注解-value: " + customAnnotation.value());
}
// 3. 解析方法上的注解
System.out.println("----------解析方法上的注解---------");
Method method = clazz.getMethod("getSampleField");
if (method.isAnnotationPresent(CustomAnnotation.class)) {
CustomAnnotation customAnnotation = method.getAnnotation(CustomAnnotation.class);
System.out.println("方法注解-name: " + customAnnotation.name());
System.out.println("方法注解-value: " + customAnnotation.value());
}
}
}
// 自定义注解(必须指定 RUNTIME 保留策略)
@Retention(RetentionPolicy.RUNTIME)
@interface CustomAnnotation {
String name() default "这是 name";
String value() default "这是 value";
}
// 测试类
@CustomAnnotation(name="SampleClass", value = "Sample Class Annotation")
class SampleClass {
@CustomAnnotation(name="sampleField", value = "Sample Field Annotation")
private String sampleField;
@CustomAnnotation(name="getSampleMethod", value = "Sample Method Annotation")
public String getSampleField() {
return sampleField;
}
public void setSampleField(String sampleField) {
this.sampleField = sampleField;
}
}
要求:反射突破泛型的编译期检查,往 ArrayList<Integer> 中添加字符串数据。
// 提示:泛型仅在编译期生效,运行时会被擦除,反射可直接调用 add 方法
ArrayList<Integer> intList = new ArrayList<>();
intList.add(100);
// 请补充反射代码,添加字符串"Hello Reflection"
要求:使用 Properties 解析配置文件,反射调用指定类的指定方法。
Student 类:
public class Student {
public void study() {
System.out.println("好好学习天天向上");
}
}
配置文件 student.properties:
className=com.java.exer.Student
methodName=study
要求:
StudentController 类是否添加 @MyController 注解;@MyRequestMapping 的方法存入 HashMap;StudentController 类:
@MyController
public class StudentController {
@MyRequestMapping
public void method1() {
System.out.println("执行了 method1()");
}
public void method2() {
System.out.println("执行了 method2()");
}
@MyRequestMapping
public void method3() {
System.out.println("执行了 method3()");
}
}
自定义注解:
@Retention(RetentionPolicy.RUNTIME)
public @interface MyController {
String name() default "这是 name";
String value() default "这是 value";
}
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRequestMapping {
String name() default "这是 name";
String value() default "这是 value";
}
反射是 Java 中极具威力的特性,核心是通过 JVM 中的类元数据突破编译期限制,实现动态化编程。掌握 Class、Constructor、Field、Method、Annotation 的使用,是理解 Spring 等框架底层原理的关键。建议结合本文案例动手实践,再完成课后作业,彻底掌握反射的核心用法。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online