从oracle的官方文档来学习annotations:
地址在:
http://docs.oracle.com/javase/tutorial/java/javaOO/annotations.html
总结如下:
Annotations我理解就是程序的一些元数据,没有它程序也是ok的。它的主要用途体现在以下几个方面:
1. 替代以前简单的注释;
比如以前的注释可能是:
/*
author: Benjamin Franklin
date: 3/27/2010
*/
class My Class {}
用Annotations可以写成:
@Author(
name = "Benjamin Franklin",
date = "3/27/2010"
)
class MyClass() { }
再复杂一点的注释:
public class Generation3List extends Generation2List {
// Author: John Doe
// Date: 3/17/2002
// Current revision: 6
// Last modified: 4/12/2004
// By: Jane Doe
// Reviewers: Alice, Bill, Cindy
// class code goes here
}
用Annotations:
@interface ClassPreamble {
String author();
String date();
int currentRevision() default 1;
String lastModified() default "N/A";
String lastModifiedBy() default "N/A";
// Note use of array
String[] reviewers();
}
@ClassPreamble (
author = "John Doe",
date = "3/17/2002",
currentRevision = 6,
lastModified = "4/12/2004",
lastModifiedBy = "Jane Doe",
// Note array notation
reviewers = {"Alice", "Bob", "Cindy"}
)
public class Generation3List extends Generation2List {
// class code goes here
}
其中,@interface是定义一个annotation的关键字,看上去像接口,其实不是。
如果要让@ClassPreamble的信息出现在javadoc生成的文档中,你必须给刚才定义的@ClassPreamble加上@Documented这个保留的annotation。
如下所示:
// import this to use @Documented
import java.lang.annotation.*;
@Documented
@interface ClassPreamble {
// Annotation element definitions
}
2. 编译器保留的注解, 例如@Deprecated, @Override, 和 @SuppressWarnings.
@Deprecated意思是这个方法过时了,你最好不要再用了,你用我就给你来个warning;
@Override是提示你这个方法是覆盖了父类的一个方法;
@SuppressWarnings是告诉编译器这个方法可能会抛出warning,但你不要告诉我啦。
3. 在runtime用这些注解信息;
一般的用法在runtime的时候JVM不会load这些annotation信息,如果要让runtime知道,就要使用java.lang.annotation.RetentionPolicy了,这是个enum,有三个可选值,
分别是
- CLASS:annotation会被记录在class文件里但不会被jvm load。
- RUNTIME:记录在class文件里也会被jvm load,可以通过反射读取。
- SOURCE:会被compiler丢弃。
具体看下面这个例子:
先定义一个annotation:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Test_Target {
public String doTestTarget();
}
@Retention(RetentionPolicy.RUNTIME) 就是上面所说的在runtime时候我也要知道注解的信息。
@Target(ElementType.FIELD) 是指这个注解可以加在Field前面(所以你加到方法签名会编译不过的),java.lang.annotation.ElementType也是一个enum,其他可选择的值包括如下,不翻译了。
CONSTRUCTOR
Constructor declaration
FIELD
Field declaration (includes enum constants)
LOCAL_VARIABLE
Local variable declaration
METHOD
Method declaration
PACKAGE
Package declaration
PARAMETER
Parameter declaration
TYPE
Class, interface (including annotation type), or enum declaration
定义了这个注解,看怎么在runtime时候访问它:
import java.lang.reflect.Field;
public class TestAnnotations {
@Test_Target(doTestTarget="Hello World !")
private String str;
public static void main(String[] args) throws Exception {
// We need to use getDeclaredField here since the field is private.
Field field = TestAnnotations.class.getDeclaredField("str");
Test_Target ann = field.getAnnotation(Test_Target.class);
if (ann != null) {
System.out.println(ann.doTestTarget());
}
}
}
注意在变量str前面使用了定义的注解,在main方法里通过反射获取到了注解中doTestTarget对应的值,所以输出是
Hello World !