zoukankan      html  css  js  c++  java
  • [03] 处理注解:反射


    1、AnnotatedElement接口

    如果没有用来读取注解的方法和工作,那么注解也就不会比注释更有用处了。使用注解的过程中,很重要的一部分就是创建于使用注解处理器。Java SE5扩展了反射机制的API,以帮助程序员快速的构造自定义注解处理器。

    Java用Annotation接口来代表程序元素前面的注解,该接口是所有Annotation类型的父接口。如在java.lang.reflect包中有一个接口AnnotatedElement,其中定义了一些注解相关的方法,如判断某元素是否标注了注解的方法:
    • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
    • 这里的传参实际上就是传入 ”某个注解.class“ 

    另外,Java在java.lang.reflect 包下新增了 AnnotatedElement 接口:
    /** 
     * Represents an annotated element of the program currently running in this
     * VM.  This interface allows annotations to be read reflectively.  All
     * annotations returned by methods in this interface are immutable and
     * serializable.  It is permissible for the caller to modify the
     * arrays returned by accessors for array-valued enum members; it will
     * have no affect on the arrays returned to other callers.
     *
     * <p>If an annotation returned by a method in this interface contains
     * (directly or indirectly) a {@link Class}-valued member referring to
     * a class that is not accessible in this VM, attempting to read the class
     * by calling the relevant Class-returning method on the returned annotation
     * will result in a {@link TypeNotPresentException}.
     *
     * <p>Similarly, attempting to read an enum-valued member will result in
     * a {@link EnumConstantNotPresentException} if the enum constant in the
     * annotation is no longer present in the enum type.
     * 
     * <p>Finally, Attempting to read a member whose definition has evolved
     * incompatibly will result in a {@link
     * java.lang.annotation.AnnotationTypeMismatchException} or an
     * {@link java.lang.annotation.IncompleteAnnotationException}.
     *
     * @since 1.5
     * @author Josh Bloch
     */
    该接口代表程序中可以接受注解的程序元素,这句话怎么理解?我们从另一头倒着来理:

    (1)Field、Method、Constructor
    在反射中我们知道的像属性、方法、构造函数等封装的类,都继承了一个类,叫AccessibleObject;

    (2)AccessibleObject 参考链接
    java.lang.reflect包中有类AccessibleObject,从类的注释可以看出,The AccessibleObject class is the base class for Field, Method and Constructor objects. It provides the ability to flag a reflected object as suppressing default Java language access control checks when it is used. 显然,它可以让一个反射对象去禁止Java语言的访问控制检测,从而能够调用对象的私有属性和方法。

    这个类实现了一个接口,就是我们提到的AnnotatedElement了,实现该接口的类(Represents an annotated element of the program currently running in this VM.  This interface allows annotations to be read reflectively.)即代表那些可注解的元素,同时可以利用反射机制读取注解。所以,它的几个主要实现类有
    • Class  类
    • Constructor  构造器
    • Field  类的成员变量
    • Method  类的方法
    • Package  类的包

    注意:如Class、Package未继承AccessibleObject,毕竟这两个类不需要所谓的访问权限设置,但是它们是实现了AnnotatedElement接口的。

    所以当我们通过反射获取某个类的AnnotatedElement对象之后,就可以调用AnnotatedElement接口定义好的几个方法:

    • //判断该程序元素上是否包含指定类型的注解,存在返回true,否则返回false
    • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);

    • //返回该程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null
    • <T extends Annotation> T getAnnotation(Class<T> annotationClass);

    • //返回该程序元素上存在的所有注解
    • Annotation[] getAnnotations();

    • //返回直接存在于该元素上的所有注解(与该接口中其他方法不同,该方法将忽略继承的注解)
    • //如果没有注解直接存在于此元素上,则返回长度为零的一个数组
    • //该方法调用者可以随意修改返回的数组,不会对其他调用者返回的数组产生影响
    • Annotation[] getDeclaredAnnotations();


    2、AnnotatedElement使用示例

    2.1 自定义注解

    /**
     * 水果名称注解
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface FruitName {
        String value() default "";
    }
    
    
    /**
     * 水果颜色注解
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface FruitColor {
        /**
         * 颜色枚举
         */
        public enum Color {BULE, RED, GREEN}
    
        /**
         * 颜色属性
         */
        public Color fruitColor() default Color.GREEN;
    }
    
    
    /**
     * 水果供应商注解
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface FruitProvider {
    
        /**
         * 供应商编号
         */
        public int id() default -1;
    
        /**
         * 供应商名称
         */
        public String name() default "";
    
        /**
         * 供应商地址
         */
        public String address() default "";
    
    }
    注意:当一个Annotation类型被定义为运行时(RUNTIME)的Annotation时,该注解才能是运行时可见,当class文件被装载时被保存在class文件中的Annotation才会被虚拟机读取。

    2.2 使用自定义注解的类

    /**
     * 苹果类
     */
    public class Apple {
    
        /**
         * 苹果名称
         */
        @FruitName("红富士")
        private String appleName;
    
        /**
         * 苹果颜色
         */
        @FruitColor(fruitColor = FruitColor.Color.RED)
        private String appleColor;
    
        /**
         * 苹果供应商
         */
        @FruitProvider(id = 1, name = "陕西红富士集团", address = "陕西省西安市延安路89号红富士大厦")
        private String appleProvider;
    
        public String getAppleName() {
            return appleName;
        }
    
        public void setAppleName(String appleName) {
            this.appleName = appleName;
        }
    
        public String getAppleColor() {
            return appleColor;
        }
    
        public void setAppleColor(String appleColor) {
            this.appleColor = appleColor;
        }
    
        public String getAppleProvider() {
            return appleProvider;
        }
    
        public void setAppleProvider(String appleProvider) {
            this.appleProvider = appleProvider;
        }
    }

    2.3 注解处理

    public class FruitInfoUtil {
    
        /**
         * 获取水果信息
         * @param clazz 类对象
         */
        public static void getFruitInfo(Class<?> clazz) {
    
            String strFruitName;
            String strFruitColor;
            String strFruitProvider;
    
            //获取该类对象包含的所有属性对象
            Field[] fields = clazz.getDeclaredFields();
    
            //遍历属性对象
            for (Field field : fields) {
                //如果属性包含的注解是FruitName
                if (field.isAnnotationPresent(FruitName.class)) {
                    FruitName fruitName = field.getAnnotation(FruitName.class);
                    strFruitName = "水果名称:" + fruitName.value();
                    System.out.println(strFruitName);
                }
                //如果属性包含的注解是FruitColor
                else if (field.isAnnotationPresent(FruitColor.class)) {
                    FruitColor fruitColor = field.getAnnotation(FruitColor.class);
                    strFruitColor = "水果颜色:" + fruitColor.fruitColor().toString();
                    System.out.println(strFruitColor);
                }
                //如果属性包含的注解是FruitProvider
                else if (field.isAnnotationPresent(FruitProvider.class)) {
                    FruitProvider fruitProvider = field.getAnnotation(FruitProvider.class);
                    strFruitProvider = "供应商编号:" + fruitProvider.id()
                            + ";供应商名称:" + fruitProvider.name()
                            + ";供应商地址:" + fruitProvider.address();
                    System.out.println(strFruitProvider);
                }
            }
        }
        
    }

    2.4 测试和结果输出

    public class TestAnnotation {
        public static void main(String[] args) {
            FruitInfoUtil.getFruitInfo(Apple.class);
        }
    }
    
    //结果输出
    水果名称:红富士
    水果颜色:RED
    供应商编号:1;供应商名称:陕西红富士集团;供应商地址:陕西省西安市延安路89号红富士大厦


    3、参考链接

  • 相关阅读:
    1063. Set Similarity
    A1047. Student List for Course
    A1039. Course List for Student
    最大公约数、素数、分数运算、超长整数计算总结
    A1024. Palindromic Number
    A1023. Have Fun with Numbers
    A1059. Prime Factors
    A1096. Consecutive Factors
    A1078. Hashing
    A1015. Reversible Primes
  • 原文地址:https://www.cnblogs.com/deng-cc/p/7462588.html
Copyright © 2011-2022 走看看