zoukankan      html  css  js  c++  java
  • Java Annotation 注解

    java_notation.html

    Java Annotation 注解

    注解:

    是Java代码中的元数据, 在创建之后的某个时刻可以使用, 代表了代码的配置信息, 代码和配置结合在一起, 存储有关程序的额外信息.

    定义注解:

    注解的定义类似interface的定义, 同其他Java接口一样, 注解也会被编译成class文件. 格式为:

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.Runtime)
    public @interface Test{
        ///
        public int id();
        public String descripteion() default "no description";
    }
    

    其中, @Target@Retention也是注解被称为元注解, 是Java提供的四种注解,后面会补充.
    @Target 代表了该注解应用的对象(如一个类或者一个函数).
    @Retention 代表了该注解在哪一个级别可用(共三种: 源码中Source, 类文件Class, 运行时Runtime).
    一般的注解中会有元素, 元素的定义类似于接口中方法的定义(成员变量类似接口的方法的定义). 但是后面可以跟一个default指定默认值.
    没有元素的注解称之为标记注解, 如元注解中的 @Documented
    注解的元素使用时是以名-值对的形式定义的, 并放在注解后的括号内, 如@Test( id = 49, desctiption = "lyb" ).

    元注解:

    元注解是Java源码中定义的四种注解, 自己定义的注解必然要借助这四种注解.

    注解解释
    @Target 表示该注解可以用于什么地方, 接受的参数为ElementType参数, 共有以下几种类型:
    CONSTRUCTOR: 构造器的声明
    FIELD: 域声明(包括enum实例)
    LOCAL_VARIABLE: 局部变量声明
    METHOD: 方法声明
    PACKAGE: 包声明
    PARAMETER: 参数声明
    TYPE: 类, 接口(包括注解类型)或enum声明
    @Retention 表示需要在什么级别保存该注释信息, 接受参数为RetentionPolicy类型:
    SOURCE: 注解将被编译器丢弃
    CLASS: 注解在class文件中可用,但是会被编译器丢弃
    RUNTIME: VM将在运行期也保留注解, 因此可以通过反射机制读取注解的信息
    @Documented 将此注解包含在Javadoc中
    @Inherited 允许子类继承父类中的注解

    元注解本身的定义也是依赖元注解的, 类似于递归.
    @Target的源码:

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
        /**
         * Returns an array of the kinds of elements an annotation type
         * can be applied to.
         * @return an array of the kinds of elements an annotation type
         * can be applied to
         */
        ElementType[] value();
    }
    

    注解解释器:

    注解和注释的区别: 如果没有处理注解的工具, 那么注解不会比注释更有用. 所以使用注解就是要有相应的注解处理器, 而注解处理器是建立在反射机制上的.

    对以VM, 在没有注解处理器的情况下, 有没有注解对于源代码编译得到的字节吗应该是一样的, 当然可能会多出注解的字节码.

    下面给出一个例子:

    注解UserCase:

    package test;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * Created by lyb on 16-11-29.
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface UserCase {
        public int id();
        public String description() default "no description";
    }
    

    使用了注解的一般类:

    package test;
    
    import java.util.List;
    
    /**
     * Created by lyb on 16-11-29.
     */
    public class PasswordUtil {
        @UserCase(id = 47, description = "Passwords must contains at last one numberic")
        public boolean validatePassword(String password){
            return password.matches("\w*\d\w*");
        }
    
        @UserCase(id = 48)
        public String encryptPassword(String password){
            return new StringBuilder(password).reverse().toString();
        }
    
        @UserCase(id = 50, description = "New passwords can't equals the used one")
        public boolean checkForNewPassword(List<String> prevPassword, String password){
            return !prevPassword.contains(password);
        }
    }
    

    真正的注解处理器:

    package test;
    
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    /**
     * Created by lyb on 16-11-29.
     */
    public class UserCaseTracker {
        public static void trackUserCases(List<Integer> userCases, Class<?> cl){
            for (Method m : cl.getDeclaredMethods()){
                UserCase uc = m.getAnnotation(UserCase.class);
                if (uc != null){
                    System.out.println("Found user case : " + uc.id()
                            + " " + uc.description());
                    userCases.remove(new Integer(uc.id()));
                }
            }
            for (int i : userCases){
                System.out.println("Warning: Missing user case !");
            }
        }
    
        public static void main(String[] args){
            List<Integer> userCases = new ArrayList<>();
            Collections.addAll(userCases, 47, 48, 49, 50);
            trackUserCases(userCases, PasswordUtil.class);
        }
    }
    

    程序的输出:

    Found user case : 47 Passwords must contains at last one numberic
    Found user case : 48 no description
    Found user case : 50 New passwords can't equals the used one
    Warning: Missing user case-49!
    

    需要注意的地方,

    1. 传给反射的参数是class类型的.

    2. 因为@UserCase 修饰的是Method, 所以通过Method得到注解对象.

    注解元素的类型:

    即在注解的interface中定义的类似函数的元素, 如int的id(), String的description().

    所有可用的注解元素的类型有:

    1. 所有基本类型(int, float, boolean)等
    2. String
    3. class
    4. enum
    5. Annotation
    6. 以上类型的数组

    需要注意的是:

    1. 不能使用任何包装类型
    2. 注解可以嵌套

    对注解元素的限制:

    注解中的元素都必须确定, 或者有默认值, 或者在注解中赋值.

    非基本类型(如自己定义的类)的值不能有null, 因此必须自己定义一些特殊值来表示某个元素不存在.

    使用多个注解的时候, 同一个注解不能重复使用.

    注解本身不支持继承, 但是被 @Inherited 修饰的类具有继承性. 同样地, 由于没有继承性, 因此要具有类似多态的注解, 就必须多定义不同参数的函数或者是类, 并且用反射函数 getDeclaredAnnotation() 来遍历得到需要的注解.

    generated by haroopad

  • 相关阅读:
    JQuery hover鼠标变换
    装饰者模式
    principle04
    Method Injection
    观察者模式
    Java SPI
    Redis--学习01
    OO设计中5大原则
    knowledge
    策略模式
  • 原文地址:https://www.cnblogs.com/putuotingchan/p/6135526.html
Copyright © 2011-2022 走看看