注解(Annotation)提供了一种安全的类似注释的机制,为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻方便的使用这些数据,用来将任何的信息或者元数据与程序元素(类、方法、成员变量等)进行关联。
Annotation其实是一种接口,通过Java的反射机制相关的API来访问Annotation信息。相关框架或工具中的类根据这些信息来决定如何使用该程序元素或改变它们的行为。
一、java.lang.annotation包
(1)Target.java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
其中@interface是一个关键字,在设计annotations的时候必须把一个类型定义为@interface,而不能用class或interface关键字。
(2)源文件Retention.java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
在上面的文件都用到了RetentionPolicy,ElementType这两个字段。
(3)RetentionPolicy.java
public enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME
}
这是一个enum类型,共有三个值,分别是SOURCE, CLASS 和 RUNTIME。
- SOURCE:代表的是这个Annotation类型的信息只会保留在程序源码里,源码如果经过了编译之后,Annotation的数据就会消失,并不会保留在编译好的.class文件里面。 如@Override里面的Retention设为SOURCE,编译成功了就不要这一些检查的信息
- ClASS:的意思是这个Annotation类型的信息保留在程序源码里,同时也会保留在编译好的.class文件里面,在执行的时候,并不会把这一些信息加载到虚拟机(JVM)中去.注意一下,当你没有设定一个Annotation类型的Retention值时,系统默认值是CLASS。
- RUNTIME:表示在源码、编译好的.class文件中保留信息,在执行的时候会把这一些信息加载到JVM中去。@Deprecated里面的Retention设为RUNTIME,表示除了在编译时会警告我们使用了哪个被Deprecated的方法,在执行的时候也可以查出该方法是否被Deprecated。
(4)ElementType.java
public enum ElementType {
TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR,
LOCAL_VARIABLE, ANNOTATION_TYPE,PACKAGE
}
@Target里面的ElementType是用来指定Annotation类型可以用在哪一些元素上:
- TYPE(类型):是指可以用在Class,Interface,Enum和Annotation类型上。
- FIELD(属性)
- METHOD(方法)
- PARAMETER(参数)
- CONSTRUCTOR(构造函数)
- LOCAL_VARIABLE(局部变量)
- ANNOTATION_TYPE
- PACKAGE(包)
如果一个Annotation类型没有指明@Target使用在哪些元素上,那么它可以使用在任何元素之上。
二、自定义注解的语法
- 使用@interface关键字定义注解。
- 成员以无参无异常方式定义,看起来是方法,实际上也表示存储数据的属性。
- 可以用default为成员指定一个默认值。
- 只能用public或默认(default)这两个访问权修饰。
- 参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和String,Enum,Class,annotations等数据类型,以及这一些类型的数组。
- 如果只有一个参数成员,最好把参数名称设为”value”,后加小括号。
- 注解类可以没有成员,这种注解称为标识注解。
- 如果需要把Annotation的数据继承给子类,那么就会用到@Inherited这一个Annotation类型。
代码实例
(1)定义两个注解,Description和Name。
Description.java
package com.ljq.test;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Description {
String value();
}
Name.java
package com.ljq.test;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//注意这里的@Target与@Description里的不同,参数成员也不同
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Name {
String originate();
String community();
}
(2)在一个类中使用注解
JavaEyer.java
package com.ljq.test;
@Description("javaeye,做最棒的软件开发交流社区")
public class JavaEyer {
@Name(originate = "创始人:robbin", community = "javaEye")
public String getName() {
return null;
}
@Name(originate = "创始人:江南白衣", community = "springside")
public String getName2() {
return "借用两位的id一用,写这一个例子,请见谅!";
}
}
(3)提取注解内容
package com.ljq.test;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
public class TestAnnotation {
public static void main(String[] args) throws Exception {
String CLASS_NAME = "com.ljq.test.JavaEyer";
Class test = Class.forName(CLASS_NAME);
Method[] method = test.getMethods();
boolean flag = test.isAnnotationPresent(Description.class);
if (flag) {
Description des = (Description) test
.getAnnotation(Description.class);
System.out.println("描述:" + des.value());
System.out.println("-----------------");
}
// 把JavaEyer这一类有利用到@Name的全部方法保存到Set中去
Set<Method> set = new HashSet<Method>();
for (int i = 0; i < method.length; i++) {
boolean otherFlag = method[i].isAnnotationPresent(Name.class);
if (otherFlag)
set.add(method[i]);
}
for (Method m : set) {
Name name = m.getAnnotation(Name.class);
System.out.println(name.originate());
System.out.println("创建的社区:" + name.community());
}
}
}
输出
描述:javaeye,做最棒的软件开发交流社区
-----------------
创始人:robbin
创建的社区:javaEye
创始人:江南白衣
创建的社区:springside
Class对象和Method对象关于注解的方法:
(1) A getAnnotation(Class annotationClass)
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
(2) Annotation[] getAnnotations()
返回此元素上存在的所有注释。
(3)boolean isAnnotationPresent(Class