美文网首页
Java自定义注解实战

Java自定义注解实战

作者: shenghaishxt | 来源:发表于2020-03-13 15:42 被阅读0次

    注解简介

    注解的本质是一个接口,该接口默认继承Annotation接口,使用@interface进行定义。注解主要有三类:元注解、自定义注解以及框架定义的注解。

    • 接口里面的成员方法称为注解的属性
    • 定义了属性,要在使用的时候给属性赋值
    • 如果定义属性时使用default关键字给属性默认初始值,则可以不进行赋值
    • 若只有一个属性且名为value,则使用时可以直接写值
    • 数组赋值时使用 { } 包裹,数组只有一个值时可以不用 { }

    元注解

    首先我们要知道什么是元注解,元注解可以看作是用在注解上的注解。基础的元注解有四个:

    • @Target() :描述注解能够作用的位置。

      • ElementType.FIELD:说明自定义的注解可以用于类的变量
      • ElementType.METHOD:说明自定义的注解可以用于类的方法
      • ElementType.TYPE:说明自定义的注解可以用于类本身、接口或 enum类型
    • @Retention() : 描述注解被保留的阶段

      • @Retention(RetentionPolicy.RUNTIME):表示注解可以一直保留到运行时,因此可以通过反射获取注解信息
      • @Retention(RetentionPolicy.CLASS):表示注解被编译器编译进 class文件,但运行时会忽略
      • @Retention(RetentionPolicy.SOURCE):表示注解仅在源文件中有效,编译时就会被忽略
    • @Documented : 描述注解是否被抽取到api文档中

    • @Inherited : 描述注解是否被子类继承

    可以看到,在描述注解被保留的阶段的时候,生命周期从长到短的顺序是RUNTIME > CLASS > SOURCE。因此,如果需要使用反射在运行时动态获取注解的信息,是必须使用@Retention(RetentionPolicy.RUNTIME)的,就像接下来要实现的例子一样。

    利用注解来校验类中的字段

    首先自定义一个注解。

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Length {
        int min();
        int max();
        String errorMsg();
    }
    

    然后定义一个Person类,包含ID、name以及sex字段,并设置set方法。

    public class Person {
        @Length(min = 8, max = 8, errorMsg = "错误!id必须为8位!")
        private String id;
    
        private String name;
    
        private String sex;
    
        public void setId(String id) {
            this.id = id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    }
    

    然后我们可以利用反射的原理编写一个测试主函数,看我们自定义的注解是否能够检测字段id是否满足设置的要求。

    import java.lang.reflect.Field;
    
    public class lengthTest {
        public static String validate(Object object) throws IllegalAccessException {
            // 通过反射获取对象的字段
            Field[] fields = object.getClass().getDeclaredFields();
    
            // 逐个字段检验,看哪个字段上标了注解
            for (Field field : fields) {
                if (field.isAnnotationPresent(Length.class)) {
                    // 如果标了注解,则通过反射获取到该字段上注解的详细信息(包括各种参数)
                    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;
        }
    
        public static void main(String[] args) throws IllegalAccessException {
            Person person = new Person();
            person.setId("1234567");
            person.setName("小美");
            person.setSex("女");
            System.out.println(validate(person));
        }
    }
    

    最后,强调一下,反射的知识真的很重要!

    相关文章

      网友评论

          本文标题:Java自定义注解实战

          本文链接:https://www.haomeiwen.com/subject/jhlkshtx.html