编程自学指南: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注解的实现原理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zl515035644

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值