5. Annotation(注解)
Annotation是一种元数据(metadata),即“Information about information”,在源代码中标记。
注解使用类Javadoc的语法,@ANNOTATION_NAME(参数),参数为KEY=VALUE的形式。
5.1 内置注解类型
内置的注解类型位于java.lang包中,不需导入,开箱即用。
5.1.1. Override
标明方法覆写了基类的方法。此注解为一种标识注解,无参数。
JDK源码如下:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
5.1.2. Deprecated
表明不推荐使用。此注解为一种标识注解,无参数。
JDK源码如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Deprecated {
}
5.1.3. SuppressWarnings
关闭类、方法、属性等的指定编译器警告。此注解接收一个String[]类型的参数。
JDK源码如下:
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
SuppressWarnings注解用法示例:
@SuppressWarnings(value={"unchecked"})
public void nonGenericsMethod( ) {
List list = new ArrayList( );
list.add("foo");
}
5.2 注解的注解
注解的注解即描述元数据的元数据,如上述注解的JDK源代码中的注解。
5.2.1 Target
标明注解可以作用的目标范围。
JDK源码如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
其中ElementType的取值为:
TYPE:类、接口(包含注解)、枚举类型
FIELD:属性(包含枚举类型的值)
METHOD:方法
PARAMETER:方法参数
CONSTRUCTOR:构造方法
LOCAL_VARIABLE:局部变量
ANNOTATION_TYPE:注解类型
- PACKAGE:包
JDK源代码:
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE
}
5.2.2 Retention
标明注解可以保持的范围。
JDK源码如下:@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
其中RetentionPolicy的取值为:
- SOURCE:源代码,编译器自动忽略
- CLASS:类,默认设置,编译器将其记录在class文件中,但虚拟机运行时不保留
- RUNTIME:运行时,编译器将其记录在class文件中,虚拟机运行时将其保留,可以通过反射获取
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
5.2.3 Documented
标明Javadoc文档中需包含此注解内容。
JDK源码如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
注:Documented注解的使用要求注解的RetentionPolicy的设置为RUNTIME
5.2.4 Inherited
标明作用于class上的注解是被自动继承的注解。
JDK源码如下:@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
注意:
1. Inherited注解的使用要求注解的RetentionPolicy的设置为RUNTIME
2. 接口上的注解即使是标明了@Inherited的注解,也不会被继承
3. 基类方法上的注解如果标明了@Inherited则会被继承,但在被子类覆写后也会丢失注解信息
5.3 自定义注解类型
注解类型本质上是一种Java的接口,但使用@interface关键字进行声明。
示例:
public @interface Todo {
public enum Severity {CRITICAL, IMPORTANT, TRIVIAL, DOCUMENTATION};
String description();
String assignedTo();
}
使用示例:
@Todo(
severity=Todo.Severity.CRITICAL,
description="Figure out the amount of order",
assignedTo="Tom"
)
public void calculate() {
// Need to finish this method later
}
5.5 新增的反射API
在java.lang.reflect包中新增了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的数组
reflect包中的相关类如Class等都实现了此接口。
注:反射要求注解的RetentionPolicy的设置为RUNTIME