注解的定义
注解就是用来做标注用:可以在类、字段变量、方法、接口等位置进行一个特殊的标记,为后续做一些诸如:代码生成、数据校验、资源整合等工作做铺垫。注解一旦对代码标注完成,后续我们就可以结合Java强大的反射机制,在运行时动态地获取到注解的标注信息,从而可以执行很多其他逻辑,完成我们想要的自动化工作。
自定义一个注解
比如说我们想要校验一个 Student 类
public class Student {
private Long id;
private String name;
private String mobile; // 校验手机号码的长度
}
首先定义注解:@Length
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Length {
int min(); // 允许字符串长度的最小值
int max(); // 允许字符串长度的最大值
String errorMsg() default "输入参数长度过长或过短"; // 自定义错误信息
}
说明:
1、注解的定义有点像定义接口 interface,但唯一不同的是前面需要加一个 @符号
2、注解的成员变量只能使用基本类型、 String或者 enum枚举,比如 int可以,但 Integer这种包装类型就不行,需注意
3、像上面 @Target、 @Retention这种加在注解定义上面的注解,我们称为 “元注解”,元注解就是专门用于给注解添加注解的注解,简单理解,元注解就是天生就有的注解,可直接用于注解的定义上
4、 @Target(xxx) 用来说明该自定义注解可以用在什么位置,比如:
ElementType.FIELD:说明自定义的注解可以用于类的变量ElementType.METHOD:说明自定义的注解可以用于类的方法ElementType.TYPE:说明自定义的注解可以用于类本身、接口或enum类型- 等等… 还有很多,如果记不住,建议现用现查
5、 @Retention(xxx) 用来说明你自定义注解的生命周期,比如:
@Retention(RetentionPolicy.RUNTIME):表示注解可以一直保留到运行时,因此可以通过反射获取注解信息@Retention(RetentionPolicy.CLASS):表示注解被编译器编译进class文件,但运行时会忽略@Retention(RetentionPolicy.SOURCE):表示注解仅在源文件中有效,编译时就会被忽略所以声明周期从长到短分别为:RUNTIME > CLASS > SOURCE ,一般来说,如果需要在运行时去动态获取注解的信息,还是得用RUNTIME,就像本文所用。
获取注解并对其进行验证
public class Verification {
public static String validate (Object object) throws IllegalAccessException {
// 首先通过反射获取object对象的类有哪些字段
Field[] fields = object.getClass().getDeclaredFields();
// for循环逐个字段校验,看哪个字段上标了注解
for (Field field : fields) {
// if判断:检查该字段上有没有标注了@Length注解
if (field.isAnnotationPresent(Length.class)) {
// 通过反射获取到该字段上标注的@Length注解的详细信息
Length length = field.getAnnotation(Length.class);
field.setAccessible(true); // 让我们在反射时能访问到私有变量
// 用过反射获取字段的实际值
int value = ((String) field.get(object)).length();
// 将字段的实际值和注解上做标示的值进行比对
if (value < length.min() || value > length.max()) {
return length.errorMsg();
}
}
}
return null;
}
}
使用注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Length {
int min(); // 允许字符串长度的最小值
int max(); // 允许字符串长度的最大值
String errorMsg() default "输入参数长度过长或过短"; // 自定义错误信息
}
编写测试类
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.setId(1L);
student.setName("Ning");
student.setMobile("13012345678");
try {
String s = Verification.validate(student);
if (s == null) {
System.out.println(student);
}else {
throw new RuntimeException(s);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}