#16. Java反射
一、项目准备与环境搭建
1. 创建Maven项目
- 打开IntelliJ IDEA → File → New → Project…
- 选择Maven
- 填写项目信息:
GroupId:com.reflection.demoArtifactId:java-reflection-tutorialVersion: 1.0-SNAPSHOT
- 点击Finish
2. 项目结构说明
java-reflection-tutorial/
├── pom.xml # Maven配置文件
└── src/
├── main/
│ └── java/
│ └── com/reflection/demo/ # 源代码目录
│ ├── Main.java # 主程序入口
│ └── Person.java # 反射操作的目标类
└── test/
二、反射基础概念与目标类
1. 创建反射操作的目标类 Person.java
package com.reflection.demo;
/**
* 反射操作的目标类
* 包含:
* 1. 私有字段和公有字段
* 2. 私有方法和公有方法
* 3. 构造方法
*/
public class Person {
// 私有字段(需要通过反射访问)
private String secretName;
// 公有字段(可以直接访问)
public int age;
// 无参构造方法
public Person() {
System.out.println("无参构造方法被调用");
}
// 带参构造方法
public Person(String name, int age) {
this.secretName = name;
this.age = age;
System.out.println("带参构造方法被调用");
}
// 公有方法
public void greet() {
System.out.println("Hello, my name is " + secretName);
}
// 私有方法(需要通过反射调用)
private void printSecret() {
System.out.println("Secret: My real name is " + secretName + ", age " + age);
}
// 公有getter方法
public String getName() {
return secretName;
}
// 公有setter方法
public void setName(String name) {
this.secretName = name;
}
@Override //@Override 注解的保留策略是 SOURCE,这意味着它只在源代码级别保留,不会在运行时保留。因此,通过反射无法在运行时获取到 @Override 注解。
public String toString() {
return "Person{name='" + secretName + "', age=" + age + "}";
}
}

三、反射核心操作详解(Main.java)
package com.reflection.demo;
import java.lang.reflect.*;
/**
* Java反射机制演示类
* 包含:
* 1. 获取Class对象的三种方式
* 2. 创建对象实例
* 3. 访问和修改字段
* 4. 调用方法
* 5. 获取构造方法
*/
public class Main {
public static void main(String[] args) {
try {
// ==================== 1. 获取Class对象的三种方式 ====================
System.out.println("=== 1. 获取Class对象的三种方式 ===");
// 方式1:通过类名.class获取(编译时已知)
Class<?> clazz1 = Person.class;
System.out.println("方式1获取的Class对象: " + clazz1.getName());
// 方式2:通过对象的getClass()方法获取(运行时已知)
Person person = new Person();
Class<?> clazz2 = person.getClass();
System.out.println("方式2获取的Class对象: " + clazz2.getName());
// 方式3:通过Class.forName()方法获取(通过全限定类名)
Class<?> clazz3 = Class.forName("com.reflection.demo.Person");
System.out.println("方式3获取的Class对象: " + clazz3.getName());
// 验证三种方式获取的是同一个Class对象
System.out.println("clazz1 == clazz2: " + (clazz1 == clazz2));
System.out.println("clazz1 == clazz3: " + (clazz1 == clazz3));
// ==================== 2. 创建对象实例 ====================
System.out.println("\n=== 2. 创建对象实例 ===");
// 获取无参构造方法
Constructor<?> noArgConstructor = clazz3.getDeclaredConstructor();
// 创建实例
Object newPerson1 = noArgConstructor.newInstance();
System.out.println("通过无参构造创建的对象: " + newPerson1);
// 获取带参构造方法
Constructor<?> paramConstructor = clazz3.getDeclaredConstructor(String.class, int.class);
// 创建实例
Object newPerson2 = paramConstructor.newInstance("Alice", 25);
System.out.println("通过带参构造创建的对象: " + newPerson2);
// ==================== 3. 访问和修改字段 ====================
System.out.println("\n=== 3. 访问和修改字段 ===");
// 获取私有字段secretName
Field secretNameField = clazz3.getDeclaredField("secretName");
// 设置可访问(私有字段需要)
secretNameField.setAccessible(true);
// 修改字段值
secretNameField.set(newPerson2, "Bob");
// 读取字段值
String name = (String) secretNameField.get(newPerson2);
System.out.println("修改后的name字段值: " + name);
// 获取公有字段age
Field ageField = clazz3.getField("age");
// 修改字段值
ageField.set(newPerson2, 30);
// 读取字段值
int age = ageField.getInt(newPerson2);
System.out.println("修改后的age字段值: " + age);
// ==================== 4. 调用方法 ====================
System.out.println("\n=== 4. 调用方法 ===");
// 调用公有方法greet()
Method greetMethod = clazz3.getMethod("greet");
greetMethod.invoke(newPerson2);
// 调用公有方法setName()
Method setNameMethod = clazz3.getMethod("setName", String.class);
setNameMethod.invoke(newPerson2, "Charlie");
// 调用公有方法getName()
Method getNameMethod = clazz3.getMethod("getName");
String currentName = (String) getNameMethod.invoke(newPerson2);
System.out.println("当前name: " + currentName);
// 调用私有方法printSecret()
Method printSecretMethod = clazz3.getDeclaredMethod("printSecret");
printSecretMethod.setAccessible(true); // 允许访问私有方法
printSecretMethod.invoke(newPerson2);
// ==================== 5. 获取构造方法 ====================
System.out.println("\n=== 5. 获取构造方法 ===");
// 获取所有构造方法
Constructor<?>[] constructors = clazz3.getDeclaredConstructors();
System.out.println("类 " + clazz3.getName() + " 的构造方法:");
for (Constructor<?> constructor : constructors) {
System.out.println(" " + constructor);
}
// 创建另一个实例
Constructor<?> anotherConstructor = clazz3.getConstructor(String.class, int.class);
Person anotherPerson = (Person) anotherConstructor.newInstance("David", 35);
System.out.println("通过另一个构造方法创建的对象: " + anotherPerson);
} catch (ClassNotFoundException e) {
System.err.println("未找到类: " + e.getMessage());
} catch (NoSuchMethodException e) {
System.err.println("未找到方法: " + e.getMessage());
} catch (InstantiationException e) {
System.err.println("无法实例化类: " + e.getMessage());
} catch (IllegalAccessException e) {
System.err.println("非法访问: " + e.getMessage());
} catch (InvocationTargetException e) {
System.err.println("方法调用异常: " + e.getMessage());
} catch (NoSuchFieldException e) {
System.err.println("未找到字段: " + e.getMessage());
}
}
}
四、运行与调试
1. 运行项目
- 右键
Main.java→ Run ‘Main.main()’ - 或点击IDEA右上角的绿色运行按钮

运行输出结果:
"C:\Program Files\Java\jdk1.8.0_202\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2.2\lib\idea_rt.jar=51618:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_202\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\rt.jar;C:\Users\lx\IdeaProjects\java-reflection-tutorial\target\classes" com.reflection.demo.Main
=== 1. 获取Class对象的三种方式 ===
方式1获取的Class对象: com.reflection.demo.Person
无参构造方法被调用
方式2获取的Class对象: com.reflection.demo.Person
方式3获取的Class对象: com.reflection.demo.Person
clazz1 == clazz2: true
clazz1 == clazz3: true
=== 2. 创建对象实例 ===
无参构造方法被调用
通过无参构造创建的对象: Person{name='null', age=0}
带参构造方法被调用
通过带参构造创建的对象: Person{name='Alice', age=25}
=== 3. 访问和修改字段 ===
修改后的name字段值: Bob
修改后的age字段值: 30
=== 4. 调用方法 ===
Hello, my name is Bob
当前name: Charlie
Secret: My real name is Charlie, age 30
=== 5. 获取构造方法 ===
类 com.reflection.demo.Person 的构造方法:
public com.reflection.demo.Person()
public com.reflection.demo.Person(java.lang.String,int)
带参构造方法被调用
通过另一个构造方法创建的对象: Person{name='David', age=35}
Process finished with exit code 0
2. 调试技巧
- 在反射调用代码处设置断点
- 右键 → Debug运行
- 在Variables视图中:
- 查看动态创建的对象状态
- 展开
this引用查看内部字段
- 使用Evaluate Expression功能:
- 输入
clazz3.getDeclaredFields()查看所有字段 - 输入
secretNameField.getName()查看字段名
- 输入
五、代码详细注释与知识点讲解
1. 获取Class对象的三种方式
// 方式1:通过类名.class获取(编译时已知)
Class<?> clazz1 = Person.class;
// 方式2:通过对象的getClass()方法获取(运行时已知)
Person person = new Person();
Class<?> clazz2 = person.getClass();
// 方式3:通过Class.forName()方法获取(通过全限定类名)
Class<?> clazz3 = Class.forName("com.reflection.demo.Person");
- 适用场景:
- 方式1:编译时已知类名(最常用)
- 方式2:运行时已有对象实例
- 方式3:通过字符串动态加载类(框架中常见)
2. 创建对象实例
// 获取无参构造方法
Constructor<?> noArgConstructor = clazz3.getDeclaredConstructor();
// 创建实例
Object newPerson1 = noArgConstructor.newInstance();
- 关键点:
getDeclaredConstructor():获取所有构造方法(包括私有)newInstance():调用构造方法创建实例
3. 访问和修改字段
// 获取私有字段secretName
Field secretNameField = clazz3.getDeclaredField("secretName");
// 设置可访问(私有字段需要)
secretNameField.setAccessible(true);
// 修改字段值
secretNameField.set(newPerson2, "Bob");
// 读取字段值
String name = (String) secretNameField.get(newPerson2);
- 关键点:
getDeclaredField():获取所有字段(包括私有)getField():只能获取公有字段setAccessible(true):绕过Java访问控制检查
4. 调用方法
// 调用公有方法greet()
Method greetMethod = clazz3.getMethod("greet");
greetMethod.invoke(newPerson2);
// 调用私有方法printSecret()
Method printSecretMethod = clazz3.getDeclaredMethod("printSecret");
printSecretMethod.setAccessible(true); // 允许访问私有方法
printSecretMethod.invoke(newPerson2);
- 关键点:
getMethod():获取公有方法getDeclaredMethod():获取所有方法(包括私有)invoke():执行方法
5. 获取构造方法
// 获取所有构造方法
Constructor<?>[] constructors = clazz3.getDeclaredConstructors();
// 创建另一个实例
Constructor<?> anotherConstructor = clazz3.getConstructor(String.class, int.class);
Person anotherPerson = (Person) anotherConstructor.newInstance("David", 35);
- 关键点:
getDeclaredConstructors():获取所有构造方法getConstructor():获取公有构造方法
六、常见问题与解决方案
1. ClassNotFoundException
- 原因:类名拼写错误或类不存在
- 解决:检查全限定类名是否正确
2. NoSuchMethodException
- 原因:方法名或参数类型不匹配
- 解决:检查方法名和参数类型
3. IllegalAccessException
- 原因:尝试访问私有成员但未设置
setAccessible(true) - 解决:对私有字段/方法调用
setAccessible(true)
4. InstantiationException
- 原因:尝试实例化抽象类、接口或数组
- 解决:确保类可以被实例化
七、反射的优缺点
优点
- 动态性:可以在运行时检查、修改类结构
- 灵活性:可以创建对象、调用方法、访问字段而无需在编译时知道它们的存在
- 框架基础:许多框架(如Spring、Hibernate)依赖反射实现核心功能
缺点
- 性能开销:反射操作比直接调用慢
- 安全限制:需要处理
SecurityManager检查 - 代码可读性差:反射代码通常难以理解和维护
反射获取Person类所有信息
下面创建一个新的类ClassInfoPrinter,它使用Java反射机制来获取并打印Person类的所有信息,包括字段、方法、构造方法、注解等。

package com.reflection.demo;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
/**
* 使用反射获取并打印类的所有信息
*/
public class ClassInfoPrinter {
public static void main(String[] args) {
try {
// 1. 获取Person类的Class对象
Class<?> personClass = Class.forName("com.reflection.demo.Person");
// 2. 打印类基本信息
System.out.println("=== 类基本信息 ===");
printClassInfo(personClass);
// 3. 打印所有字段
System.out.println("\n=== 字段信息 ===");
printFieldsInfo(personClass);
// 4. 打印所有方法
System.out.println("\n=== 方法信息 ===");
printMethodsInfo(personClass);
// 5. 打印所有构造方法
System.out.println("\n=== 构造方法信息 ===");
printConstructorsInfo(personClass);
// 6. 打印类实现的接口
System.out.println("\n=== 实现的接口 ===");
printInterfaces(personClass);
// 7. 打印父类信息
System.out.println("\n=== 父类信息 ===");
printSuperClass(personClass);
// 8. 打印类注解(如果有)
System.out.println("\n=== 类注解 ===");
printAnnotations(personClass);
} catch (ClassNotFoundException e) {
System.err.println("未找到Person类: " + e.getMessage());
}
}
/**
* 打印类基本信息
*/
private static void printClassInfo(Class<?> clazz) {
System.out.println("类名: " + clazz.getName());
System.out.println("简单类名: " + clazz.getSimpleName());
System.out.println("包名: " + clazz.getPackage().getName());
System.out.println("是否为接口: " + clazz.isInterface());
System.out.println("是否为枚举: " + clazz.isEnum());
System.out.println("是否为注解: " + clazz.isAnnotation());
System.out.println("是否为数组: " + clazz.isArray());
System.out.println("是否为原始类型: " + clazz.isPrimitive());
System.out.println("修饰符: " + Modifier.toString(clazz.getModifiers()));
}
/**
* 打印所有字段信息
*/
private static void printFieldsInfo(Class<?> clazz) {
// 获取所有字段(包括继承的字段)
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println("\n字段名: " + field.getName());
System.out.println("字段类型: " + field.getType().getName());
System.out.println("修饰符: " + Modifier.toString(field.getModifiers()));
// 尝试获取字段的注解(如果有)
Annotation[] annotations = field.getAnnotations();
if (annotations.length > 0) {
System.out.println("注解:");
for (Annotation annotation : annotations) {
System.out.println(" " + annotation);
}
} else {
System.out.println("注解: 无");
}
}
}
/**
* 打印所有方法信息
*/
private static void printMethodsInfo(Class<?> clazz) {
// 获取所有方法(不包括继承的方法)
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println("\n方法名: " + method.getName());
System.out.println("返回类型: " + method.getReturnType().getName());
// 打印参数信息
System.out.print("参数类型: ");
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 0) {
System.out.println("无");
} else {
for (Class<?> paramType : parameterTypes) {
System.out.print(paramType.getName() + " ");
}
System.out.println();
}
System.out.println("修饰符: " + Modifier.toString(method.getModifiers()));
// 打印异常信息
System.out.print("声明的异常: ");
Class<?>[] exceptionTypes = method.getExceptionTypes();
if (exceptionTypes.length == 0) {
System.out.println("无");
} else {
for (Class<?> exceptionType : exceptionTypes) {
System.out.print(exceptionType.getName() + " ");
}
System.out.println();
}
}
}
/**
* 打印所有构造方法信息
*/
private static void printConstructorsInfo(Class<?> clazz) {
// 获取所有构造方法
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("\n构造方法: " + constructor.getName());
// 打印参数信息
System.out.print("参数类型: ");
Class<?>[] parameterTypes = constructor.getParameterTypes();
if (parameterTypes.length == 0) {
System.out.println("无");
} else {
for (Class<?> paramType : parameterTypes) {
System.out.print(paramType.getName() + " ");
}
System.out.println();
}
System.out.println("修饰符: " + Modifier.toString(constructor.getModifiers()));
// 打印异常信息
System.out.print("声明的异常: ");
Class<?>[] exceptionTypes = constructor.getExceptionTypes();
if (exceptionTypes.length == 0) {
System.out.println("无");
} else {
for (Class<?> exceptionType : exceptionTypes) {
System.out.print(exceptionType.getName() + " ");
}
System.out.println();
}
}
}
/**
* 打印实现的接口
*/
private static void printInterfaces(Class<?> clazz) {
Class<?>[] interfaces = clazz.getInterfaces();
if (interfaces.length == 0) {
System.out.println("未实现任何接口");
} else {
for (Class<?> iface : interfaces) {
System.out.println("接口: " + iface.getName());
}
}
}
/**
* 打印父类信息
*/
private static void printSuperClass(Class<?> clazz) {
Class<?> superClass = clazz.getSuperclass();
if (superClass == null) {
System.out.println("没有父类(Object类)");
} else {
System.out.println("父类: " + superClass.getName());
}
}
/**
* 打印类注解
*/
private static void printAnnotations(Class<?> clazz) {
// 获取类上的注解
Annotation[] classAnnotations = clazz.getAnnotations();
if (classAnnotations.length == 0) {
System.out.println("无类注解");
} else {
System.out.println("类注解:");
for (Annotation annotation : classAnnotations) {
System.out.println(" " + annotation);
}
}
// 获取方法上的注解
System.out.println("\n方法注解:");
Method[] methods = clazz.getDeclaredMethods();
if (methods.length == 0) {
System.out.println("无方法");
} else {
for (Method method : methods) {
Annotation[] methodAnnotations = method.getAnnotations();
if (methodAnnotations.length == 0) {
System.out.println("方法 " + method.getName() + ": 无注解");
} else {
System.out.println("方法 " + method.getName() + " 的注解:");
for (Annotation annotation : methodAnnotations) {
System.out.println(" " + annotation);
}
}
}
}
}
}
代码说明
-
获取Class对象:
- 使用
Class.forName()动态加载Person类
- 使用
-
打印类基本信息:
- 类名、简单类名、包名
- 类类型(接口、枚举、注解、数组等)
- 修饰符(public、final等)
-
字段信息:
- 字段名、类型
- 修饰符和注解
-
方法信息:
- 方法名、返回类型
- 参数列表和异常声明
-
构造方法信息:
- 参数列表和异常声明
-
接口和父类信息:
- 实现的接口和继承的父类
-
注解信息:
- 类上的注解(虽然Person类没有注解,但展示了如何获取)
运行结果
运行ClassInfoPrinter后,看到以下输出:
"C:\Program Files\Java\jdk1.8.0_202\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2.2\lib\idea_rt.jar=64236:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_202\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\rt.jar;C:\Users\lx\IdeaProjects\java-reflection-tutorial\target\classes" com.reflection.demo.ClassInfoPrinter
=== 类基本信息 ===
类名: com.reflection.demo.Person
简单类名: Person
包名: com.reflection.demo
是否为接口: false
是否为枚举: false
是否为注解: false
是否为数组: false
是否为原始类型: false
修饰符: public
=== 字段信息 ===
字段名: secretName
字段类型: java.lang.String
修饰符: private
注解: 无
字段名: age
字段类型: int
修饰符: public
注解: 无
=== 方法信息 ===
方法名: toString
返回类型: java.lang.String
参数类型: 无
修饰符: public
声明的异常: 无
方法名: getName
返回类型: java.lang.String
参数类型: 无
修饰符: public
声明的异常: 无
方法名: setName
返回类型: void
参数类型: java.lang.String
修饰符: public
声明的异常: 无
方法名: greet
返回类型: void
参数类型: 无
修饰符: public
声明的异常: 无
方法名: printSecret
返回类型: void
参数类型: 无
修饰符: private
声明的异常: 无
=== 构造方法信息 ===
构造方法: com.reflection.demo.Person
参数类型: 无
修饰符: public
声明的异常: 无
构造方法: com.reflection.demo.Person
参数类型: java.lang.String int
修饰符: public
声明的异常: 无
=== 实现的接口 ===
未实现任何接口
=== 父类信息 ===
父类: java.lang.Object
=== 类注解 ===
无类注解
方法注解:
方法 toString: 无注解
方法 getName: 无注解
方法 setName: 无注解
方法 greet: 无注解
方法 printSecret: 无注解
Process finished with exit code 0
@Override 注解的保留策略是 SOURCE,这意味着它只在源代码级别保留,不会在运行时保留。因此,通过反射无法在运行时获取到 @Override 注解。
学习要点
-
反射API:
Class类是反射的入口getDeclaredFields()/getDeclaredMethods()获取所有成员Modifier类解析修饰符
-
动态性:
- 可以在运行时检查类的结构
- 不需要预先知道类的具体实现
-
异常处理:
- 反射操作可能抛出多种异常,需要适当处理
-
性能考虑:
- 反射操作比直接调用慢,应谨慎使用
继续练习可以尝试:
- 添加自定义注解到Person类,然后通过反射读取
- Java动态代理
- 注解处理器
- 反射在框架中的应用(如Spring IoC容器)
- 实现一个简单的对象序列化/反序列化工具

171

被折叠的 条评论
为什么被折叠?



