Java 反射与注解详解
zhezhongyun 2025-05-14 18:25 55 浏览
一、反射(Reflection)
反射允许程序在运行时动态获取类的信息(如类名、方法、字段、构造器等),并操作类或对象(如创建实例、调用方法、访问字段)。它是实现框架(如Spring、MyBatis)和动态代理的核心技术。
1. 反射核心 API
1.1 获取 Class 对象
// 方式1:通过类名.class
Class<?> clazz1 = String.class;
// 方式2:通过对象.getClass()
String str = "hello";
Class<?> clazz2 = str.getClass();
// 方式3:通过Class.forName()
Class<?> clazz3 = Class.forName("java.lang.String");1.2 获取类信息
// 获取类名
String className = clazz.getName(); // java.lang.String
String simpleName = clazz.getSimpleName(); // String
// 获取字段(包括私有字段)
Field[] fields = clazz.getDeclaredFields();
// 获取方法(包括私有方法)
Method[] methods = clazz.getDeclaredMethods();
// 获取构造器
Constructor<?>[] constructors = clazz.getDeclaredConstructors();1.3 操作对象
// 创建实例(通过无参构造器)
Object instance = clazz.newInstance(); // 已过时,建议用构造器
Constructor<?> constructor = clazz.getDeclaredConstructor();
Object instance = constructor.newInstance();
// 调用方法
Method method = clazz.getDeclaredMethod("methodName", int.class, String.class);
method.setAccessible(true); // 访问私有方法
Object result = method.invoke(instance, 123, "arg");
// 访问/修改字段
Field field = clazz.getDeclaredField("fieldName");
field.setAccessible(true); // 访问私有字段
Object value = field.get(instance);
field.set(instance, "new value");2. 应用场景
- 动态代理:通过 Proxy 和 InvocationHandler 实现接口的代理。
- 框架设计:如Spring的依赖注入(@Autowired)、MyBatis的Mapper动态实现。
- 序列化/反序列化:JSON库(如Jackson)通过反射读取对象字段。
二、注解(Annotation)
注解是代码中的元数据,用于标记类、方法或字段,提供额外信息供编译时或运行时处理。Java内置注解(如 @Override)和自定义注解均可通过反射读取。
1. 注解的定义
1.1 元注解(定义注解的注解)
- @Target:指定注解可应用的目标(类、方法、字段等)。
@Target(ElementType.METHOD) // 只能修饰方法- @Retention:指定注解保留策略。
@Retention(RetentionPolicy.RUNTIME) // 运行时保留(反射可读取)- @Documented:注解是否出现在Javadoc中。
- @Inherited:注解是否可被子类继承。
1.2 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "default value"; // 属性
int priority() default 1;
}2. 注解的使用
public class MyClass {
@MyAnnotation(value = "test", priority = 2)
public void myMethod() { ... }
}3. 注解的解析(通过反射)
Method method = MyClass.class.getMethod("myMethod");
if (method.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
String value = annotation.value(); // "test"
int priority = annotation.priority(); // 2
}三、反射与注解结合应用
1. 模拟 Spring 的依赖注入
public class MyContainer {
private Map<String, Object> beans = new HashMap<>();
public void init() throws Exception {
// 扫描包下的类
Class<?> clazz = Class.forName("com.example.MyService");
if (clazz.isAnnotationPresent(Component.class)) {
Object instance = clazz.newInstance();
beans.put(clazz.getSimpleName(), instance);
}
}
public Object getBean(String name) {
return beans.get(name);
}
}2. 自定义 ORM 框架(字段映射)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
String name();
}
public class User {
@Column(name = "user_id")
private int id;
@Column(name = "user_name")
private String name;
}
// 反射解析注解生成SQL
public String buildInsertSQL(Object obj) {
StringBuilder sql = new StringBuilder("INSERT INTO ");
Class<?> clazz = obj.getClass();
sql.append(clazz.getSimpleName()).append(" (");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Column.class)) {
Column column = field.getAnnotation(Column.class);
sql.append(column.name()).append(", ");
}
}
sql.delete(sql.length()-2, sql.length()).append(") VALUES (...)");
return sql.toString();
}3. 自定义单元测试框架
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest {
String description() default "";
}
public class TestRunner {
public static void main(String[] args) throws Exception {
Class<?> testClass = Class.forName("com.example.MyTestClass");
for (Method method : testClass.getDeclaredMethods()) {
if (method.isAnnotationPresent(MyTest.class)) {
method.invoke(testClass.newInstance());
}
}
}
}四、注意事项
- 反射的性能
- 反射操作比直接调用慢,频繁调用需缓存 Method、Field 对象。
- 避免在性能敏感场景过度使用反射。
- 安全性
- 反射可以绕过访问权限(setAccessible(true)),需谨慎使用。
- 安全管理器(SecurityManager)可限制反射操作。
- 注解的保留策略
- 若注解的 @Retention 设置为 SOURCE 或 CLASS,则运行时无法通过反射读取。
总结
- 反射是动态操作类的工具,适用于框架、动态代理等场景,但需注意性能和安全。
- 注解为代码添加元数据,结合反射可实现灵活的逻辑控制(如依赖注入、ORM映射)。
深入学习方向:
- 动态代理(Proxy 和 InvocationHandler)
- 注解处理器(APT):在编译时处理注解(如Lombok)。
- ASM 字节码操作:直接修改字节码实现高级功能。
相关推荐
- Python入门学习记录之一:变量_python怎么用变量
-
写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...
- python变量命名规则——来自小白的总结
-
python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...
- Python入门学习教程:第 2 章 变量与数据类型
-
2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...
- 绘制学术论文中的“三线表”具体指导
-
在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...
- Python基础语法知识--变量和数据类型
-
学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...
- 一文搞懂 Python 中的所有标点符号
-
反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...
- Python变量类型和运算符_python中变量的含义
-
别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...
- 从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序
-
在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...
- Python中下划线 ‘_’ 的用法,你知道几种
-
Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...
- 解锁Shell编程:变量_shell $变量
-
引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...
- 一文学会Python的变量命名规则!_python的变量命名有哪些要求
-
目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...
- 更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for
-
src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...
- C++第五课:变量的命名规则_c++中变量的命名规则
-
变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....
- Rust编程-核心篇-不安全编程_rust安全性
-
Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...
- 探秘 Python 内存管理:背后的神奇机制
-
在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- opacity 属性 (32)
- transition 属性 (33)
- 1-1. 变量声明 (31)
