🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 第四章第二节--处理注解 标签(空格分隔): 廖雪峰 --- ## 注解的处理分类 - 注解本身对代码逻辑没有任何影响 - SOURCE类型的注解在编译期就被丢弃了. - CLASS类型的注解仅保留在class文件中,处理的时候需要专用工具进行操作. - RUNTIME类型的注解在运行期间可以被读取. - 如何使用注解由工具决定. 因为个人写的代码不涉及编译器,所以无法处理SOURCE类型的代码,CLASS类型的注解同时是由处理class类型的工具来使用非常少见.只有RUNTIME类型的注解可以在运行的时候使用Java代码来读取,所以我们讨论的如何处理注解,只针对的RUNTIME类型的注解. ## 如何读取RUNTIME类型的注解. - Annotation也是Class - 所有的Annotation继承java.lang.annotation.Annotation - 使用反射API 方法1:判断是否存在 使用反射API读取Annotation: - Class.isAnnotationPresent(Class) - Field.isAnnotationPresent(Class) - Method.isAnnotationPresent(Class) - Constructor.isAnnotationPresent(Class) ![判断是不是Annotation](http://p0b921qfc.bkt.clouddn.com/18-5-18/1429737.jpg) 方法2:直接获取 - Class.getAnnotation(Class) - Field.getAnnotation(Class) - Method.getAnnotation(Class) - Constructor.getAnnotation(Class) ![获取Annotation](http://p0b921qfc.bkt.clouddn.com/18-5-18/55968607.jpg) 两种使用反射API来读取Annotation的方式: ![反射读取Annotation](http://p0b921qfc.bkt.clouddn.com/18-5-18/42287307.jpg) 例子: 定义一个NotNull的注解 ```java import java.lang.annotation.ElementType; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) //必须有 public @interface NotNull { } ``` 定义一个边界检测的注解 ```java import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Range { int min() default 1; int max() default 100; } ``` 应用该注解的bean对象. ```java public class Person { @NotNull public String name; @Range(max = 20) public int age; public Person(String name, int age) { this.name = name; this.age = age; } public String toString() { return "Person(name=" + name + ", age=" + age + ")"; } } ``` 检测类,对注解进行检测. ```java import java.lang.reflect.Field; public class Main { public static void main(String[] args) throws Exception { Person p1 = new Person("Xiao Ming", 25); Person p2 = new Person(null, 15); checkPerson(p1); checkPerson(p2); } static void checkPerson(Person p) throws Exception { System.out.println("check " + p + "..."); Class c = Person.class; for (Field f : c.getFields()) { checkField(f, p); } } static void checkField(Field f, Person p) throws Exception { if (f.isAnnotationPresent(NotNull.class)) { Object r = f.get(p); if (r == null) { System.out.println("Error: field " + f.getName() + " is null."); } } if (f.isAnnotationPresent(Range.class)) { Range range = f.getAnnotation(Range.class); int n = (Integer) f.get(p); if (n < range.min() || n > range.max()) { System.out.println("Error: field " + f.getName() + " is out of range."); } } } } ``` ## 小节小结 - 可以在运行期通过反射读取RUNTIME类型的注解.(不能漏写@Rentention(RetentionPolicy.RUNTIME)) - 可以通过工具处理注解来实现相应的功能. - 对javaBean的属性值规则进行检查. - JUnit会自动运行@Test注解的测试方法.