注解(也被称为元数据)为我们在代码添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻方便的使用这些数据。注解是java SE5种的重要的语言变化之一。注解使得我们能够以将由编译期来测试和验证的格式,存储有关程序的额外信息。注解可以用来生成描述符文件,甚至或是新的类定义,并且有助于减轻编写“样板”代码的负担。通过使用注解,我们可以将这些元数据保存在Java源代码中,并利用annotation API为自己的注解构造处理工具,同时,注解的优点还包括:更加干净易读的代码以及编译期类型检查等。

基本语法

注解的语法比较简单,除了@符号的使用之外,它基本和Java固有的语法一致。Java内置了三种,定义在Java.lang中的注解: 1、@Override 表示当前的方法定义将覆盖超类中的方法。 2、@Deprecated 这个方法或类不再建议使用。在新版本中有其他方法或类可以代替这个使用,以后的版本也不会再更新这个方法或类 3、@SuppressWarnings,关闭不当的编译器警告信息。 4、@SafeVarargs,jdk 1.7,抑制编译器警告,只能用在参数长度可变的方法或构造方法上,且方法必须声明为static或final,否则会出现编译错误。一个方法使用@SafeVarargs注解的前提是,开发人员必须确保这个方法的实现中对泛型类型参数的处理不会引发类型安全问题。

Java还提供了另外四种元注解,专门负责新注解的创建。 1、@Target,表示该注解可以用在什么地方。ElementType参数包括: TYPE:类、接口(包括注解类型)或者enum声明 FIELD:域声明(包括enum实例) METHOD:方法声明 PARAMETER:参数声明 CONSTRUCTOR:构造器声明 LOCAL_VARIABLE:局部变量声明 ANNOTATION_TYPE:注解类型声明 PACKAGE:包声明 TYPE_PARAMETER:类型属性声明 TYPE_USE:使用类型

2、@Retention,表示需要在什么级别保存该注解信息。RetentionPolicy参数包括: SOURCE:注解将被编译期丢弃 CLASS:注解在class文件可用,但会被VM丢弃 RUNTIME:VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息。

3、@Documented,将此注解包含在Javadoc中。

4、@Inherited、允许子类继承父类中的注解。

JDK 1.8 加了几个注解 5、@Native,表明定义一个常量值的字段可以被引用从本地代码。

6、@Repeatable ,新注解讲语法糖转化为注解值为数组形式。

7、@FunctionalInterface , 用于编译级错误检查,表示必须符合函数式接口。

下面来看例子:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
    public int id();
    public String descrpition () default "no description";
}

class PasswordUtils{
    @UseCase(id=1,descrpition = "description1")
    public boolean volidatePassword(String password){
        return (password.matches("\\w*\\d\\w*"));
    }

    @UseCase(id=2)
         public String encryptPassword(String password){
        return new StringBuffer(password).reverse().toString();
    }

    @UseCase(id=3 ,descrpition = "description3")
    public boolean checkPassword(String password){
        return password.contains("\\*");
    }
}

大多数时候,我们主要是定义自己的注解,并编写自己的注解处理器来处理它们。

public class UseCaseTracker {
    public static void trackUseCases(List<Integer> useCases,Class<?> cl){
        for(Method m:cl.getDeclaredMethods()){
            UseCase uc = m.getAnnotation(UseCase.class);
            if(uc!=null){
                System.out.println("Found Use Case:"+uc.id()+" "+uc.descrpition());
                useCases.remove(uc.id());
            }
        }

        for(int i:useCases){
            System.out.println("warning :Missing use case " + i);
        }
    }

    public static void main(String[]args){
        List<Integer> list = new ArrayList<>();
        Collections.addAll(list,1,2,3,4,5);
        trackUseCases(list,PasswordUtils.class);
    }
}

注解元素

标签@UseCase中包含int元素id,以及一个String元素description。注解元素可用的类型有:所有基本类型、String、Class、enum、Annotation、以上类型的数组。如果你使用了其他元素类型,编译器就会报错。

编译器对元素的默认值有些过分挑剔。首先,元素不能有不确定的值,也就是说,元素必须要么具有默认值,要么在使用注解时提供元素的值。其次,对于非基本类型的元素,无论是在源代码或是在注解接口中定义默认值,都不能以null作为其值。

同时注解不支持继承。

总结 注解提供了一种结构化的,并且具有类型检查能力的新途径,从而使得程序员能够为代码加入元数据,而不会导致代码杂乱且难以阅读。使用注解能够帮助我们避免编写累赘的部署描述文件,以及其他生成的文件,与注释性文字相比,注解绝对更适用于描述类的相关的信息。

参看文献: thinking in java