JAVA 注解的几大作用及使用方法详解

最近一直 Jersey,发现里面有大量的注解,以前虽然看了一些,但是资料都感觉写的很复杂,今天希望通过一个例子,用最简单的方法分享一下到底什么是注解。

一、创建一个注解

package com.taobao.Test;

import java.lang.annotation.*;

/*

  • 定义注解 Test

  • 为方便测试:注解目标为类 方法,属性及构造方法

  • 注解中含有三个元素 id ,name 和 gid;

  • id 元素 有默认值 0
    */
    @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TestA {
    String name();

    int id() default 0;

    Class<Long> gid();
    }

大家看着可能有些不明白,没事儿,第一次都这样,可以回头在慢慢看,这里先简单解释一下:

  • @Target:是声明在哪里使用,聪明的你看 E 文就明白差不多了吧
  • @Retention:声明什么时候运行。CLASS、RUNTIME 和 SOURCE 这三种,分别表示注解保存在类文件、JVM 运行时刻和源代码中。只有当声明为 RUNTIME 的时候,才能够在运行时刻通过反射 API 来获取到注解的信息。
  • @interface:用来声明一个注解

二、创建一个使用注解的类

package com.taobao.Test;

import java.util.HashMap;
import java.util.Map;

/**

  • 这个类专门用来测试注解使用
  • @author tmser
    */

@TestA(name = "type", gid = Long.class)
// 类成员注解
public class UserAnnotation {

@TestA(name </span>= "param", id = 1, gid = Long.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 类成员注解</span>
<span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Integer age;

@TestA(name </span>= "construct", id = 2, gid = Long.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 构造方法注解</span>
<span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> UserAnnotation() {

}

@TestA(name </span>= "public method", id = 3, gid = Long.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 类方法注解</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> a() {
    Map</span>&lt;String, String&gt; m = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap&lt;String, String&gt;(0<span style="color: rgba(0, 0, 0, 1)">);
}

@TestA(name </span>= "protected method", id = 4, gid = Long.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 类方法注解</span>
<span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> b() {
    Map</span>&lt;String, String&gt; m = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap&lt;String, String&gt;(0<span style="color: rgba(0, 0, 0, 1)">);
}

@TestA(name </span>= "private method", id = 5, gid = Long.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 类方法注解</span>
<span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> c() {
    Map</span>&lt;String, String&gt; m = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap&lt;String, String&gt;(0<span style="color: rgba(0, 0, 0, 1)">);
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> b(Integer a) {

}

}

其实就是往注解里面添加参数。

三、使用注解

package com.taobao.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class ParseAnnotation {

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 简单打印出UserAnnotation 类中所使用到的类注解 该方法只打印了 Type 类型的注解
 * 
 * </span><span style="color: rgba(128, 128, 128, 1)">@throws</span><span style="color: rgba(0, 128, 0, 1)"> ClassNotFoundException
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> parseTypeAnnotation() <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ClassNotFoundException {
    Class clazz </span>= Class.forName("com.taobao.Test.UserAnnotation"<span style="color: rgba(0, 0, 0, 1)">);

    Annotation[] annotations </span>=<span style="color: rgba(0, 0, 0, 1)"> clazz.getAnnotations();
    </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (Annotation annotation : annotations) {
        TestA testA </span>=<span style="color: rgba(0, 0, 0, 1)"> (TestA) annotation;
        System.out.println(</span>"id= \"" + testA.id() + "\"; name= \"" + testA.name() + "\"; gid = " +<span style="color: rgba(0, 0, 0, 1)"> testA.gid());
    }<br>        //输出 id= "0"; name= "type"; gid = class java.lang.Long
}

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 简单打印出UserAnnotation 类中所使用到的方法注解 该方法只打印了 Method 类型的注解
 * 
 * </span><span style="color: rgba(128, 128, 128, 1)">@throws</span><span style="color: rgba(0, 128, 0, 1)"> ClassNotFoundException
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> parseMethodAnnotation() {
    Method[] methods </span>= UserAnnotation.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">.getDeclaredMethods();
    </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (Method method : methods) {
        </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
         * 判断方法中是否有指定注解类型的注解
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
        <span style="color: rgba(0, 0, 255, 1)">boolean</span> hasAnnotation = method.isAnnotationPresent(TestA.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
        </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (hasAnnotation) {
            </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
             * 根据注解类型返回方法的指定类型注解
             </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
            TestA annotation </span>= method.getAnnotation(TestA.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
            System.out.println(</span>"method = " + method.getName() + " ; id = " + annotation.id() + " ; description = " +<span style="color: rgba(0, 0, 0, 1)"> annotation.name() </span>+ "; gid= " +<span style="color: rgba(0, 0, 0, 1)"> annotation.gid());
        }
    }
}

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 简单打印出UserAnnotation 类中所使用到的方法注解 该方法只打印了 Method 类型的注解
 * 
 * </span><span style="color: rgba(128, 128, 128, 1)">@throws</span><span style="color: rgba(0, 128, 0, 1)"> ClassNotFoundException
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> parseConstructAnnotation() {
    Constructor[] constructors </span>= UserAnnotation.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">.getConstructors();
    </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (Constructor constructor : constructors) {
        </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
         * 判断构造方法中是否有指定注解类型的注解
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
        <span style="color: rgba(0, 0, 255, 1)">boolean</span> hasAnnotation = constructor.isAnnotationPresent(TestA.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
        </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (hasAnnotation) {
            </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
             * 根据注解类型返回方法的指定类型注解
             </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
            TestA annotation </span>= (TestA) constructor.getAnnotation(TestA.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
            System.out.println(</span>"constructor = " + constructor.getName() + " ; id = " + annotation.id() + " ; description = " +<span style="color: rgba(0, 0, 0, 1)"> annotation.name() </span>+ "; gid= " +<span style="color: rgba(0, 0, 0, 1)"> annotation.gid());
        }
    }
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> main(String[] args) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ClassNotFoundException {
    parseTypeAnnotation();
    parseMethodAnnotation();
    parseConstructAnnotation();
}

}

运行输出:

id= "0"; name= "type"; gid = class java.lang.Long
method = c ; id = 5 ; description = private method; gid= class java.lang.Long
method = a ; id = 3 ; description = public method; gid= class java.lang.Long
method = b ; id = 4 ; description = protected method; gid= class java.lang.Long
constructor = com.taobao.Test.UserAnnotation ; id = 2 ; description = construct; gid= class java.lang.Long

如果你还有疑问,想要知道为什么调用诸如:clazz.getAnnotations(); 就返回接口类型的数据,那么可以参考如下内容:

四、AnnotatedElement 接口

JDK 源代码如下:

public interface AnnotatedElement {
        boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
        <T extends Annotation> T getAnnotation(Class<T> annotationClass);
        Annotation[] getAnnotations();
        Annotation[] getDeclaredAnnotations();
}

 

说明一下:

  • isAnnotationPresent:判断是否标注了指定注解
  • getAnnotation:获取指定注解,没有则返回 null
  • getAnnotations:获取所有注解,包括继承自基类的,没有则返回长度为 0 的数组
  • getDeclaredAnnotations:获取自身显式标明的所有注解,没有则返回长度为 0 的数组