当前位置: 首页 > news >正文

编程自学指南:java程序设计开发,反射与注解,反射机制,注解

反射与注解

教学目标

  1. 理解反射机制的核心原理与应用场景

  2. 掌握注解的定义与使用方法

  3. 能够通过反射动态操作类、方法和字段

  4. 结合反射与注解实现灵活的程序设计


一、课程引入

1.1 为什么需要反射与注解?

  • 反射

    • 运行时动态获取类信息(如框架中自动装配对象)

    • 突破封装访问私有成员(慎用!)

  • 注解

    • 为代码添加元数据(如@Override标记重写方法)

    • 替代XML配置,简化开发(如Spring的@Autowired

1.2 生活类比

  • 反射:像“X光透视”,查看程序内部结构

  • 注解:像“标签”,为代码添加说明或指令


二、反射机制

2.1 反射核心API

类/接口作用
Class表示类或接口
Field表示类的成员变量
Method表示类的方法
Constructor表示类的构造方法

2.2 获取Class对象的三种方式

// 方式1:类名.class  
Class<String> clazz1 = String.class;  

// 方式2:对象.getClass()  
String str = "Java";  
Class<?> clazz2 = str.getClass();  

// 方式3:Class.forName()  
Class<?> clazz3 = Class.forName("java.lang.String");
案例1:动态加载类并创建对象

Class<?> clazz = Class.forName("com.example.User");  
Object user = clazz.newInstance();  // 调用无参构造  
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);  
Object user2 = constructor.newInstance("张三", 25); 

2.3 操作私有成员

案例2:访问私有方法

public class Secret {  
    private void hiddenMethod() {  
        System.out.println("秘密方法被调用!");  
    }  
}  

// 反射调用  
Secret obj = new Secret();  
Method method = Secret.class.getDeclaredMethod("hiddenMethod");  
method.setAccessible(true);  // 突破私有限制  
method.invoke(obj); 

三、注解

3.1 内置注解

  • @Override:标记方法重写

  • @Deprecated:标记已过时的方法

  • @SuppressWarnings:抑制编译器警告

3.2 元注解(注解的注解)

元注解作用
@Target定义注解可应用的目标(如方法、字段)
@Retention定义注解保留策略(SOURCE/CLASS/RUNTIME)
@Documented注解包含在Javadoc中

3.3 自定义注解

案例3:定义字段校验注解

@Target(ElementType.FIELD)  
@Retention(RetentionPolicy.RUNTIME)  
public @interface NotNull {  
    String message() default "字段不能为空";  
}  

// 应用注解  
public class User {  
    @NotNull(message = "姓名不能为空")  
    private String name;  
}

3.4 注解处理器(反射解析注解)

案例4:实现注解校验逻辑

public static void validate(Object obj) throws IllegalAccessException {  
    for (Field field : obj.getClass().getDeclaredFields()) {  
        if (field.isAnnotationPresent(NotNull.class)) {  
            field.setAccessible(true);  
            Object value = field.get(obj);  
            if (value == null) {  
                NotNull anno = field.getAnnotation(NotNull.class);  
                throw new IllegalArgumentException(anno.message());  
            }  
        }  
    }  
}  

// 测试  
User user = new User();  
validate(user);  // 抛出异常:姓名不能为空

四、综合案例

4.1 案例5:简易ORM框架

// 定义表名注解  
@Target(ElementType.TYPE)  
@Retention(RetentionPolicy.RUNTIME)  
public @interface Table {  
    String name();  
}  

// 定义字段注解  
@Target(ElementType.FIELD)  
@Retention(RetentionPolicy.RUNTIME)  
public @interface Column {  
    String name();  
    String type();  
}  

// 应用注解  
@Table(name = "users")  
public class User {  
    @Column(name = "user_id", type = "INT")  
    private int id;  

    @Column(name = "user_name", type = "VARCHAR(50)")  
    private String name;  
}  

// 生成SQL建表语句  
public static String generateCreateTable(Class<?> clazz) {  
    if (!clazz.isAnnotationPresent(Table.class)) return null;  
    Table table = clazz.getAnnotation(Table.class);  
    StringBuilder sql = new StringBuilder("CREATE TABLE " + table.name() + " (\n");  

    for (Field field : clazz.getDeclaredFields()) {  
        if (field.isAnnotationPresent(Column.class)) {  
            Column column = field.getAnnotation(Column.class);  
            sql.append("  ").append(column.name()).append(" ").append(column.type()).append(",\n");  
        }  
    }  
    sql.deleteCharAt(sql.length() - 2);  // 删除末尾逗号  
    sql.append(");");  
    return sql.toString();  
}  

// 输出结果:  
// CREATE TABLE users (  
//   user_id INT,  
//   user_name VARCHAR(50)  
// );

五、常见错误与最佳实践

5.1 常见错误

  • 错误1:忽略注解的保留策略

    @Retention(RetentionPolicy.SOURCE)  
    public @interface MyAnnotation {}  
    // 运行时无法通过反射获取该注解
  • 错误2:反射修改final字段

    Field field = String.class.getDeclaredField("value");  
    field.setAccessible(true);  
    field.set("Hello", new char[] {'H','i'});  // 抛出IllegalAccessException

5.2 最佳实践

  • 反射

    • 优先使用公共API,避免操作私有成员

    • 缓存反射结果(如Method对象)提升性能

  • 注解

    • 明确@Target@Retention策略

    • 结合工具(如APT)生成代码


六、总结与练习

6.1 总结

  • 反射:动态操作类结构,但破坏封装性,需谨慎使用

  • 注解:为代码添加元数据,需配合处理器实现功能

6.2 课后任务

  1. 实现一个JSON序列化工具(通过反射将对象转为JSON字符串,支持@JsonIgnore注解忽略字段)

  2. 自定义一个@Test注解,标记测试方法并通过反射自动运行

  3. 预习下一节课:Lambda表达式与Stream API

6.3 扩展挑战

  • 阅读Spring框架源码,分析@Autowired注解的实现原理

相关文章:

  • 【商城实战(31)】从0到1:商城项目部署全攻略
  • 提升模型准确性的关键技术与实践指南
  • Qt5中视口(ViewPort)与窗口(Window)
  • WordPress顶部菜单自定义的方法
  • Android studio运行报错处理
  • 反射、反射调用以及修改成员变量,成员方法,构造函数、反射的应用
  • Ubuntu22.04 安装 Isaac gym 中出现的问题
  • jEasyUI 基本的拖动和放置
  • JPom使用Docker方式构建SpringBoot项目详解
  • 从被动响应到主动防御——IT 应急演练平台 v3.0.1 重构企业安全免疫系统
  • PHP:从入门到进阶的全方位指南
  • 在 Django 中通过 `/media/xxxx` URL 访问上传资源的安全性与实践
  • 原生微信小程序实现导航漫游(Tour)
  • 鸿蒙开发:了解应用级配置信息
  • CUDA编程(6):CUDA流、并发内核执行、重叠核函数执行与内核传输、流回调
  • JavaScript基础篇:六、 函数基础
  • 记一次排查与解决docker容器(java程序)内存占用过大的问题
  • 【蓝桥杯速成】| 1.暴力解题
  • 深入理解 HTML 链接:网页导航的核心元素
  • 前端npm包- CropperJS
  • 老人将房产遗赠给外孙,三个女儿却认为遗嘱应无效,法院判了
  • 《单身情歌》制作人韩贤光去世,林志炫发文悼念
  • 牛市早报|中美经贸高层会谈达成重要共识,取得实质性进展
  • 王毅同印度国家安全顾问多瓦尔通电话
  • 印控克什米尔地区再次传出爆炸声
  • 中美经贸高层会谈将在午餐后继续