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><String, String> m = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap<String, String>(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><String, String> m = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap<String, String>(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><String, String> m = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap<String, String>(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 的数组