概念
标记注解
An annotation without any elements is called a marker annotation.
@Documented
@Documented
用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
注解(元数据)
JDK5添加注解的原因
Annotations are partly motivated(使产生动机;激发…的积极性) by a general trend toward combining metadata with
source-code files, instead of keeping it in external documents. They are also a response to feature pressure from other languages like C#.
注解的好处
They provide information that you need to fully describe your program, but that cannot be expressed in Java. Thus, annotations allow you to store extra information about your program in a format that is tested and verified by the compiler.
Annotations can be used to generate descriptor files or even new class definitions and help ease the burden of writing "boilerplate" code.
Using annotations, you can keep this metadata in the Java source code,and have the advantage of cleaner looking code, compile-time type checking and the annotation API to help build processing tools for your annotations.
使用XML的坏处
Whenever you use an external descriptor file, you end up with two separate sources of information about a class, which usually leads to code synchronization problems. This also requires that programmers working on the project must know about editing the descriptor as well as how to write Java programs.
Java自带的注解
• @Override, to indicate(表明;指出;预示;象征) that a method definition is intended to override a method in
the base class. This generates a compiler error if you accidentally misspell the method name or give an improper signature.
• @Deprecated, to produce a compiler warning if this element is used.
• @SuppressWarnings, to turn off inappropriate compiler warnings. This annotation is allowed but not supported in earlier releases of Java SE5 (it was ignored).
Four additional annotation types support the creation of new annotations.
基础语法
空注解
Annotation definitions look a lot like interface definitions. In fact, they compile to class files like any other Java interface:
// : net/mindview/atunit/Test.java
// The @Test tag.
package net.mindview.atunit;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
// @Target(ElementType.METHOD)
// 如果可以应用到所有的地方,可以不用写@Target
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
} /// :~
Apart from(apart from:除…之外;且不说;并且) the @
symbol, the definition of @Test
is much like that of an empty interface. An annotation definition also requires the meta-annotations @Target
and @Retention
.@Target
defines where you can apply this annotation (a method or a field, for example).@Retention
defines whether the annotations are available in the source code (SOURCE
),in the class files (CLASS
), or at run time (RUNTIME
).
给注解添加元素
Annotations will usually contain elements to specify values in your annotations.Elements look like interface methods, except that you can declare default values.
// : annotations/UseCase.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
public int id();
public String description() default "no description";
} /// :~
跟定义注解相关的注解
@Target
Where this annotation can be applied. The possible ElementType
arguments are:
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
@Retention
How long the annotation information is kept. The possible RetentionPolicy
arguments are:
SOURCE
: Annotations are discarded by the compiler.
CLASS
: Annotations are available in the class file by the compiler but can be discarded by the VM.
RUNTIME
: Annotations are retained by the VM at run time, so they may be read reflectively.
@Documented
Include this annotation in the Javadocs.
@Inherited
Allow subclasses to inherit parent annotations.
注解元素的类型(换句话说就是方法的返回值类型)
- All primitives (
int
,float
,boolean
etc.) String
Class
-
Enum
s -
Annotation
s -
Array
s of any of the above
import java.awt.List;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationElementTypes {
// Invalid type Float for the annotation attribute AnnotationElementTypes.height; only primitive
// type, String, Class, annotation, enumeration are permitted or 1-dimensional arrays thereof
// public Float height();
public int age() default 1;
public String value() default "no name";
public Class> useClass() default String.class;
public NestedAnnotation useAnnotation() default @NestedAnnotation("nestedAnnotation");
public int[] age2() default 1;
public String[] value2() default {"no name", "name2"};
public Class>[] useClass2() default String.class;
public NestedAnnotation[] useAnnotation2() default {@NestedAnnotation("nestedAnnotation"),
@NestedAnnotation("nestedAnnotation2")};
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface NestedAnnotation {
public String value();
}
@AnnotationElementTypes(age = 10, value = "have name", useAnnotation = @NestedAnnotation("test"),
age2 = {12, 34}, value2 = {"value", "value3"}, useClass2 = {String.class, List.class},
useAnnotation2 = {@NestedAnnotation("test")})
class Test {
}
注解元素的默认值
所有的注解元素都必须有值,如果没有默认值则用户必须提供;
所有的注解元素不允许为null
。
// : annotations/SimulatingNull.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SimulatingNull {
public int id() default -1;
// The value for annotation attribute SimulatingNull.description must be a constant expression
// public String description() default null;
public String description() default "";
} /// :~
注解元素的名字是value
的时候
If you define an element on an annotation with the name value
, then as long as it is the only element type specified you don’t need to use the name-value pair syntax; you can just specify the value in parentheses.
注解不支持继承
编写注解处理器
Without tools to read them, annotations are hardly more useful than comments.
// : annotations/UseCaseTracker.java
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class UseCaseTracker {
public static void trackUseCases(List useCases, Class> cl) {
for (Method m : cl.getDeclaredMethods()) {
UseCase uc = m.getAnnotation(UseCase.class);
if (uc != null) {
System.out.println("Found Use Case:" + uc.id() + " " + uc.description());
useCases.remove(new Integer(uc.id()));
}
}
for (int i : useCases) {
System.out.println("Warning: Missing use case-" + i);
}
}
public static void main(String[] args) {
List useCases = new ArrayList();
Collections.addAll(useCases, 47, 48, 49, 50, 51);
trackUseCases(useCases, PasswordUtils.class);
}
}