Java Annotation 注解

java_notation.htmljavascript

Java Annotation 注解

注解:

是Java代码中的元数据, 在建立以后的某个时刻能够使用, 表明了代码的配置信息, 代码和配置结合在一块儿, 存储有关程序的额外信息.php

定义注解:

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

@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" ).html

元注解:

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

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

元注解自己的定义也是依赖元注解的, 相似于递归.
@Target的源码:node

@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();
}

注解解释器:

注解和注释的区别: 若是没有处理注解的工具, 那么注解不会比注释更有用. 因此使用注解就是要有相应的注解处理器, 而注解处理器是创建在反射机制上的.nginx

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

下面给出一个例子:github

注解UserCase:web

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