网站首页 > java教程 正文
一、反射(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 字节码操作:直接修改字节码实现高级功能。
- 上一篇: Java 注释
- 下一篇: java代码助理之注释
猜你喜欢
- 2025-04-24 Spring 最常用的 7 大类注解,史上最强整理
- 2025-04-24 Java注解知识精华系列
- 2025-04-24 哥,厉害,一文讲完了Spring的各种注解...
- 2025-04-24 Java注解的高级用法:从入门到精通
- 2025-04-24 小技巧,IDEA中创建类时,如何自动给类加注释?
- 2025-04-24 SpringBoot 常用注解总结超详细
- 2025-04-24 Java @Data注解
- 2025-04-24 学会在代码中写注释
- 2025-04-24 java代码助理之注释
- 2025-04-24 Java 注释
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)