所谓注解,是代码里做的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。通过使用注解,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充的描述源代码的信息(这些信息被存储在注解的“name=value”的键值对中)。代码分析工具、开发工具和部署工具可以通过这些补充的描述源代码信息进行验证或者进行部署。注解类似于修饰符一样被使用,可以用于包、类、构造方法、方法、成员变量、参数、局部变量的声明。
需要注意的是,注解被用来为程序元素(类、方法、成员变量等)设置元数据,它不影响程序代码的执行,无论增加、删除注解程序的执行都不受任何影响。如果希望让程序中的注解起一定作用,只有通过配套的工具对注解中的元数据信息进行提取、访问,根据这些元数据增加额外功能和处理等。访问和处理注解的工具统称APT(Annotion Processing Tool)。
一、自定义注解
注解类型的定义和接口类型的定义差不多,只是在interface前面多了一个“@”。如:
package test;
/**
* 自定义注解
*/
public @interface myAnnotation {
//定义属性
String value() default "ss";
}
接下来就是使用注解:
package test;
/**
* 自定义注解
*/
public @interface myAnnotation {
//定义属性
String value() default "ss";
}
/**
* 使用注解
*/
@myAnnotation("abc")
class UserMyAnnotation{
}
可能有个疑问,怎么没有使用value,而直接写abc了,abc到底传给谁了?其实这里有个约定,如果使用注解时没有显式指定属性名,却指定了属性值,而这个注解又有名为value的属性,就将这个值赋给value属性。
二、元注解
元注解就是对注解进行注解的注解,就是作用在注解上的注解类型,分别是Target、Retention、Documented和Inherited。
1,目标Targe,以指定这个注解类型可以应用于程序的哪些元素上。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
只能接受ElementType类型的数组,下面看看Elementype:
2,Retention,决定注解的生命周期,注意注解只有保存到class文件里才能被读出来。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
只接受RetentionPolicy的数组:
3,Document,这个注解和文档类型有关。在默认情况下,在使用javadoc自动生成文档时,注解将被忽略,但是如果想在文档中包含注解,必须使用定义Documented。另外,定义Documented的注解必须设置Retention的值为RetentionPolicy.RUNTIME。
4,Inherited。在类中的protected和public成员都将被子类继承,但是父类上的注解默认情况下并不会被子类继承。如果要让这个注解可以被子类上继承,就必须给这个注解类型定义上添加Inherited注解。
三、利用反射获取注解信息
前面讨论了如何自定义注解,如何来获取注解中的信息,并用这些信息来完成一定功能呢?解决这个问题,就需要反射机制。需要注意的是,反射是在运行时获取信息的,因此,要用反射获取注解的相关信息,这个注解必须是用@Retention(RetentionPolicy.RUNTIME)声明的。
java.lang.reflect.AnnotatedElement接口中定义了四种反射性读取注解信息的方法。
java.lang.Class和java.lang.reflect的Constructor、Field、Method、Package类都实现了AnnotationElement接口。
package test;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
/**
* 自定义注解
*/
@Target(value={ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface myAnnotation {
//定义属性
String value() default "ss";
}
/**
* 使用注解
*/
@myAnnotation("class")
class UserMyAnnotation{
@myAnnotation(value="method")
@Deprecated
public void show(){
}
}
public class Test {
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
//获取类上的注解信息
myAnnotation my = UserMyAnnotation.class.getAnnotation(myAnnotation.class);
if(my!=null)
System.out.println(my.value());
//获取方法上的注解信息
Method m = UserMyAnnotation.class.getMethod("show");
Annotation[] annotations = m.getAnnotations();
for (Annotation a:annotations)
System.out.println(a.annotationType().getName());
}
}
结果:
参考书籍:Java基础与案例开发详解