JDK1.5开始增加了Annotation功能,该功能可用于:
1、类;
2、构造方法;
3、成员变量;
4、方法
5、参数
等的声明;
该功能并不影响程序的运行,但是会对编译器警告等辅助工具产生影响。本文将介绍Annotation功能的使用方法。
1、定义Annotation类型
在定义Annotation类型时,也需要用到来定义接口的interface关键字,但需要在interface关键字前加一个@符号,即表示定义Annotation类型的关键字为@interface,这个关键字的隐含意思是继承了java.lang.annotation.Annotation接口。例如,下面的代码就定义了一个Annotation类型。
public @interface NoMemberAnnotation{}
上面定义的Annotation类型@NoMemberAnnotation未包含任何成员,这样的Annotation类型被称为marker annotation。下面的代码定义了一个只包含一个成员的Annotation类型。
public @interface OneMemberAnnotatino{ String value(); }
String: 成员类型。可用的成员类型有:
1)String;
2)Class;
3)基本类型;
4)枚举;
5)Annotation;
value:成员的名称。如果在所定义的Annotation类型中只包含一个成员,通常将成员命名为value;
下面代码定义了一个包含多个成员的Annotation类型:
public @interface MoreMemberAnnotation{ String describe(); Class type(); }
在为Annotation类型定义成员时,也可以为成员设置默认值。例如,下面的代码在定义Annotation类型时就为成员设置了默认值。
public @interface DefaultValueAnnotation{ String describe() default "<默认值>"; Class type(0 default void.class; }
在定义Annotation类型时,还可以通过Annotation类型@Target来设置Annotation类型使用的程序元素种类。如果未设置@Target,则表示适用于所有程序元素。枚举类ElementType中的枚举常量用来设置@Target,如下:
- ANNOTATION_TYPE :表示用于Annotation类型
- TYPE : 表示用于类、接口和枚举,以及Annotation类型
- CONSTRUCTOR : 表示用于构造方法
- FIELD : 表示用于成员变量和枚举常量
- METHOD :表示用于方法
- PARAMETER :表示用于参数
- LOCAL_VARIABLE :表示用于局部变量
- PACKAGE :表示用于包
通过Annotation类型的@Retention可以设置Annotation的有效范围。枚举类RetentionPolicy中的枚举常量用于设置@Retention,如果没有设置,那么默认为CLASS常量的范围,如下所示:
- SOURCE :表示不编译Annotation到类文件中,有效范围最小
- CLASS :表示编译Annotation到类文件中,但是在运行时不加载Annotation到JVM中
- RUNTIME :表示在运行时加载Annotation到JVM中,有效范围最大
2、访问Annotation信息
如果在定义Annotation类型时将@Retention设置为RetetionPolicy.RUNTIME,那么在运行程序时通过反射就可以获取到相关的Annotation信息,如获取构造方法、字段和方法的Annotation信息。
类Constructor、Field和Method继承了AccessibleObject类,而AccessibleObject类实现了AnnotatedElement,因此也就是说,Constructor、FIeld、Method均可以使用AccessibleObject实现的方法来操作注解。(注:这里Class类直接实现了AnnotatedElement不是继承AccessibleObject)
下面,我们看看AccessibleObject继承来的方法:
<T extends Annotation> getAnnotation(Class<T> annotationClass);
如果该元素存在annotationClass类型的注释,则返回该注释,否则返回null;
Annotation[] getAnnotations()
返回该元素的所有注解
Annotation[] getDeclaredAnnotation()
返回直接存在于该元素的注解(例如继承而来的注解不会被返回)
boolean isAccessible()
该元素是否执行安全检查(安全检查如:变量设置了private属性不可以直接访问,设置为取消检查则可以反问该元素)
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
该元素是否存在annotationClass注解
static void setAccessible(AccessibleObject[] array, boolean flag)
为一组元素设置是否执行安全检查
void setAccessible(boolean flag)
为该元素设置是否执行安全检查
3、DEMO
package cn.lay.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * annotation demo * @ClassName: AnnotationDemo * @Description: * @author: lay * @date: Mar 18, 2018 */ @Test( value = "test", ages = {23, 23, 34, 35, 34}, bookEnum = BookEnum.JAVA, cls = String.class, test2s = {@Test2(), @Test2("lay"), @Test2("zhang"), @Test2("wu")} ) public class AnnotationDemo { public static void main(String[] args) { // 判断是否注解了该类型 if (AnnotationDemo.class.isAnnotationPresent(Test.class)) { // 获取该注解 Test annotation = AnnotationDemo.class.getAnnotation(Test.class); // 取值 String value = annotation.value(); // 输出 System.out.println("value=" + value); int[] ages = annotation.ages(); for (int age : ages) { System.out.println("age=" + age); } BookEnum bookEnum = annotation.bookEnum(); System.out.println("bookName=" + bookEnum.getBookName());; Class<?> cls = annotation.cls(); System.out.println("class=" + cls.getName()); Test2[] test2s = annotation.test2s(); for (Test2 test2 : test2s) { System.out.println("test2=" + test2.value()); } } } } /** * 定义注解 * @ClassName: Test * @Description: * @author: lay * @date: Mar 18, 2018 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Test{ String value(); int[] ages(); BookEnum bookEnum(); Class<?> cls(); Test2[] test2s(); } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface Test2{ String value() default "lily"; } enum BookEnum{ JAVA("java"), SQL("sql"); private String bookName; public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } private BookEnum(String bookName) { this.bookName = bookName; } }
控制台打印:
value=test age=23 age=23 age=34 age=35 age=34 bookName=java class=java.lang.String test2=lily test2=lay test2=zhang test2=wu