全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-11 6 分钟 ✍️ juanwangdev

Java运行时注解

运行时注解通过反射读取,是实现框架配置功能的核心技术。

注解保留策略

只有 @Retention(RetentionPolicy.RUNTIME) 的注解才能在运行时通过反射获取。

Java
@Retention(RetentionPolicy.RUNTIME)  // 必须是RUNTIME
@Target(ElementType.TYPE)
public @interface Table {
    String name() default "";
}

反射读取注解

类注解

Java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {
    String name();
}

@Table(name = "t_user")
public class User {}

// 反射获取
Class<User> clazz = User.class;

// 检查是否存在注解
boolean hasAnnotation = clazz.isAnnotationPresent(Table.class);

// 获取注解
Table table = clazz.getAnnotation(Table.class);
if (table != null) {
    String tableName = table.name();  // "t_user"
}

方法注解

Java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface GetMapping {
    String value();
}

public class UserController {
    @GetMapping("/users")
    public List<User> listUsers() { return null; }
}

// 反射获取
Class<?> clazz = UserController.class;
Method method = clazz.getMethod("listUsers");

GetMapping mapping = method.getAnnotation(GetMapping.class);
String path = mapping.value();  // "/users"

字段注解

Java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
    String name() default "";
    boolean nullable() default true;
}

public class User {
    @Column(name = "user_name", nullable = false)
    private String username;
}

// 反射获取
Class<?> clazz = User.class;
Field field = clazz.getDeclaredField("username");

Column column = field.getAnnotation(Column.class);
String columnName = column.name();      // "user_name"
boolean nullable = column.nullable();    // false

参数注解

Java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Param {
    String value();
}

public void save(@Param("name") String name,
                 @Param("age") int age) {}

// 反射获取
Method method = clazz.getMethod("save", String.class, int.class);
Parameter[] params = method.getParameters();

for (Parameter param : params) {
    Param p = param.getAnnotation(Param.class);
    if (p != null) {
        System.out.println(p.value());  // "name", "age"
    }
}

注解API汇总

方法作用
isAnnotationPresent(Class)检查是否存在指定注解
getAnnotation(Class)获取单个注解
getAnnotations()获取所有注解
getAnnotationsByType(Class)获取重复注解
getDeclaredAnnotations()获取本类声明的注解

实战:简易ORM框架

定义注解

Java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {
    String name();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
    String name() default "";
    boolean primaryKey() default false;
}

实体类

Java
@Table(name = "t_user")
public class User {
    @Column(name = "id", primaryKey = true)
    private Long id;

    @Column(name = "username")
    private String username;

    @Column(name = "email")
    private String email;
}

ORM处理器

Java
public class OrmHelper {

    public static String getTableName(Class<?> clazz) {
        Table table = clazz.getAnnotation(Table.class);
        return table != null ? table.name() : clazz.getSimpleName().toLowerCase();
    }

    public static Map<String, Object> getColumnValues(Object obj) throws Exception {
        Map<String, Object> map = new LinkedHashMap<>();
        Class<?> clazz = obj.getClass();

        for (Field field : clazz.getDeclaredFields()) {
            Column column = field.getAnnotation(Column.class);
            if (column != null) {
                field.setAccessible(true);
                String columnName = column.name().isEmpty() ?
                    field.getName() : column.name();
                map.put(columnName, field.get(obj));
            }
        }
        return map;
    }

    public static String getPrimaryKey(Class<?> clazz) {
        for (Field field : clazz.getDeclaredFields()) {
            Column column = field.getAnnotation(Column.class);
            if (column != null && column.primaryKey()) {
                return column.name().isEmpty() ? field.getName() : column.name();
            }
        }
        return null;
    }
}

生成SQL

Java
User user = new User();
user.setId(1L);
user.setUsername("张三");
user.setEmail("zhang@example.com");

String table = OrmHelper.getTableName(User.class);
Map<String, Object> values = OrmHelper.getColumnValues(user);
String pk = OrmHelper.getPrimaryKey(User.class);

// 生成INSERT语句
StringBuilder sql = new StringBuilder("INSERT INTO " + table + " (");
sql.append(String.join(", ", values.keySet()));
sql.append(") VALUES (");
sql.append(values.values().stream()
    .map(v -> "'" + v + "'")
    .collect(Collectors.joining(", ")));
sql.append(")");

// INSERT INTO t_user (id, username, email) VALUES ('1', '张三', 'zhang@example.com')

注意事项

注解成员必须有默认值或使用时赋值,不能为 null

反射读取字段注解时需要 setAccessible(true) 访问私有字段

getAnnotations() 包含继承的注解,getDeclaredAnnotations() 只返回本类声明

@Inherited 只对类注解有效,方法和字段注解不会继承

要点总结

  1. 运行时注解必须使用 @Retention(RetentionPolicy.RUNTIME)
  2. 通过反射API:getAnnotation()、isAnnotationPresent() 读取注解
  3. 类、方法、字段、参数都支持注解反射
  4. 广泛应用于ORM、依赖注入、Web路由等框架场景

📝 发现内容有误?点击此处直接编辑

← 上一篇 Java编译时注解
下一篇 → IO 与 NIO 性能对比
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库