Java注解详解:定义、使用与自定义注解
Java注解详解:定义、使用与自定义注解
概述
注解(Annotation)是Java 5引入的元数据机制,它可以添加到代码元素(类、方法、字段等)上,提供额外的信息。注解不会直接影响代码的执行,但可以被编译器、运行时环境或框架读取和处理。
1. 内置注解
import java.util.*;
public class BuiltInAnnotations {
// @Override:标记重写父类方法
@Override
public String toString() {
return "BuiltInAnnotations{}";
}
// @Deprecated:标记已弃用
@Deprecated
public void oldMethod() {
System.out.println("This method is deprecated");
}
// @SuppressWarnings:抑制警告
@SuppressWarnings("unchecked")
public void uncheckedOperation() {
List list = new ArrayList();
list.add("Hello");
String str = (String) list.get(0);
}
// @FunctionalInterface:标记函数式接口
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}
// @SafeVarargs:安全可变参数
@SafeVarargs
public static <T> List<T> asList(T... elements) {
return Arrays.asList(elements);
}
public static void main(String[] args) {
BuiltInAnnotations obj = new BuiltInAnnotations();
System.out.println(obj);
// 使用deprecated方法(会产生警告)
obj.oldMethod();
}
}
2. 自定义注解
基本自定义注解
import java.lang.annotation.*;
// 定义自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
String value() default "";
int priority() default 0;
String[] tags() default {};
}
// 使用自定义注解
public class AnnotationUser {
@MyAnnotation(value = "Hello", priority = 1, tags = {"tag1", "tag2"})
public void annotatedMethod() {
System.out.println("被注解的方法");
}
@MyAnnotation(value = "World")
public void anotherMethod() {
System.out.println("另一个被注解的方法");
}
public void normalMethod() {
System.out.println("普通方法");
}
}
注解的元注解
import java.lang.annotation.*;
// @Retention:定义注解的保留策略
@Retention(RetentionPolicy.RUNTIME) // RUNTIME:运行时保留
@Target(ElementType.TYPE) // @Target:定义注解可以应用的元素
@Documented // @Documented:包含在JavaDoc中
@Inherited // @Inherited:子类继承父类的注解
public @interface MyAnnotation2 {
String value() default "";
}
// RetentionPolicy三种策略:
// SOURCE:只在源码中保留,编译后丢失
// CLASS:在class文件中保留,运行时丢失
// RUNTIME:运行时保留,可以通过反射获取
// ElementType多种类型:
// TYPE:类、接口、枚举
// METHOD:方法
// FIELD:字段
// CONSTRUCTOR:构造方法
// PARAMETER:参数
// PACKAGE:包
3. 注解处理
运行时注解处理(反射)
import java.lang.annotation.*;
import java.lang.reflect.*;
// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Table {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Column {
String value();
boolean nullable() default true;
int length() default 255;
}
// 使用注解的实体类
@Table("users")
class User {
@Column(value = "id", nullable = false)
private Long id;
@Column(value = "name", length = 100)
private String name;
@Column(value = "email", nullable = false, length = 200)
private String email;
public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
// Getter和Setter方法
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
// 注解处理器
public class AnnotationProcessor {
public static String generateSQL(Class<?> clazz) {
StringBuilder sql = new StringBuilder();
// 检查类注解
if (clazz.isAnnotationPresent(Table.class)) {
Table table = clazz.getAnnotation(Table.class);
sql.append("CREATE TABLE ").append(table.value()).append(" (\n");
// 处理字段注解
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if (field.isAnnotationPresent(Column.class)) {
Column column = field.getAnnotation(Column.class);
sql.append(" ").append(column.value()).append(" ");
// 根据字段类型生成SQL类型
sql.append(getSQLType(field.getType()));
if (!column.nullable()) {
sql.append(" NOT NULL");
}
if (i < fields.length - 1) {
sql.append(",");
}
sql.append("\n");
}
}
sql.append(");");
}
return sql.toString();
}
private static String getSQLType(Class<?> type) {
if (type == Long.class || type == long.class) {
return "BIGINT";
} else if (type == Integer.class || type == int.class) {
return "INT";
} else if (type == String.class) {
return "VARCHAR(255)";
} else if (type == Boolean.class || type == boolean.class) {
return "BOOLEAN";
}
return "TEXT";
}
public static void main(String[] args) {
String sql = generateSQL(User.class);
System.out.println("生成的SQL:");
System.out.println(sql);
}
}
4. 编译时注解处理
import java.lang.annotation.*;
import java.lang.reflect.*;
// 编译时注解处理器
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
@interface Log {
String level() default "INFO";
}
class Service {
@Log(level = "DEBUG")
public void processData() {
System.out.println("Processing data...");
}
public void processMoreData() {
System.out.println("Processing more data...");
}
}
// 注解处理器(简化示例)
public class CompileTimeProcessor {
public static void process(Class<?> clazz) {
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(Log.class)) {
Log log = method.getAnnotation(Log.class);
System.out.println("Method: " + method.getName());
System.out.println("Log level: " + log.level());
}
}
}
public static void main(String[] args) {
process(Service.class);
}
}
5. 实际应用示例
验证框架
import java.lang.annotation.*;
import java.util.*;
// 验证注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface NotNull {
String message() default "不能为空";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Size {
int min() default 0;
int max() default Integer.MAX_VALUE;
String message() default "长度不符合要求";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Email {
String message() default "邮箱格式不正确";
}
// 验证异常
class ValidationException extends Exception {
public ValidationException(String message) {
super(message);
}
}
// 验证器
class Validator {
public static void validate(Object obj) throws ValidationException {
Class<?> clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
try {
Object value = field.get(obj);
// NotNull验证
if (field.isAnnotationPresent(NotNull.class)) {
if (value == null) {
NotNull notNull = field.getAnnotation(NotNull.class);
throw new ValidationException(notNull.message());
}
}
// Size验证
if (field.isAnnotationPresent(Size.class) && value instanceof String) {
Size size = field.getAnnotation(Size.class);
String str = (String) value;
if (str.length() < size.min() || str.length() > size.max()) {
throw new ValidationException(size.message());
}
}
// Email验证
if (field.isAnnotationPresent(Email.class) && value instanceof String) {
Email email = field.getAnnotation(Email.class);
String str = (String) value;
if (!str.matches("^[A-Za-z0-9+_.-]+@(.+)$")) {
throw new ValidationException(email.message());
}
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
// 使用示例
class UserForm {
@NotNull(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "用户名长度必须在3-20之间")
private String username;
@NotNull(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
public UserForm(String username, String email) {
this.username = username;
this.email = email;
}
}
public class ValidationExample {
public static void main(String[] args) {
// 测试有效数据
try {
UserForm validUser = new UserForm("alice", "alice@example.com");
Validator.validate(validUser);
System.out.println("验证通过");
} catch (ValidationException e) {
System.out.println("验证失败: " + e.getMessage());
}
// 测试无效数据
try {
UserForm invalidUser = new UserForm("ab", "invalid-email");
Validator.validate(invalidUser);
System.out.println("验证通过");
} catch (ValidationException e) {
System.out.println("验证失败: " + e.getMessage());
}
}
}
6. 最佳实践
- 选择合适的保留策略:根据使用场景选择SOURCE、CLASS或RUNTIME
- 合理使用元注解:@Target、@Retention、@Documented等
- 提供默认值:注解元素应该有合理的默认值
- 保持简单:注解应该简洁明了
- 文档化注解:清楚地文档化注解的用途和元素
总结
注解是Java中强大的元数据机制,它提供了在代码中添加额外信息的方式。通过注解,可以实现编译时检查、运行时处理等功能。掌握注解的定义、使用和处理,是编写高质量Java程序的重要技能。