Java注解(Annotation)是JDK1.5引入的注释机制。Java语言中的类、方法、变量、参数和包等都可以被标注。Java注解是一种引用数据类型,编译之后也是生成.class文件。
元注解
用来标“注解类型”的注解称为元注解。JDK1.5定义了4个标准的元注解类型,用来提供对其他注解类型作说明。
-
@Target
注解:该注解说明被标注的注解的使用范围;@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
@Target
注解源码如上,可以看到Target注解包含一个ElementType[]
属性,ElementType
是一个枚举类,其值及作用如下:public enum ElementType { // 可以标注类、接口(包括注解)、枚举声明 TYPE, // 可标注属性(包括枚举常量)声明 FIELD, // 可标注方法声明 METHOD, // 可标注形参声明 PARAMETER, // 可标注构造函数声明 CONSTRUCTOR, // 可标注局部变量声明 LOCAL_VARIABLE, // 可标注注解声明 ANNOTATION_TYPE, // 可标记包声明 PACKAGE, TYPE_PARAMETER, TYPE_USE }
可以看到
Target
注解本身被@Target(ElementType.ANNOTATION_TYPE)
注解修饰,说明Target
注解只能出现注解声明语句前。当一个注解中有属性,那么必须给属性赋值,除非该属性有default指定的默认值。
-
@Retetion
:该注解用来标注被标注注解的生命周期,其源代码如下:@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { RetentionPolicy value(); } public enum RetentionPolicy { // 注解被保留在java源文件中,编译器会忽略这些注解(有点类似注释) SOURCE, // 编译器会将这些注解保留在字节码文件(.class文件)中,但虚拟机运行时不需要读取 // 默认行为,当定义注解时没显示声明Retention时默认使用@Retention(RetentionPolicy.CLASS) CLASS, // 编译器会将这些注解保存在字节码文件中,虚拟机在运行时可以通过反射读取。 RUNTIME }
-
@Documented
:标记注解是否包含在用户文档中; -
@Inherited
:被该注解标注的注解具有继承性,Demo如下;// 自定义两个注解MyAnno1和MyAnno2,其中MyAnno1标注为@Inherited。 // Base类使用MyAnno1和MyAnno2标注,Sub类继承Base @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface MyAnno1 {} @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnno2 {} @MyAnno1 @MyAnno2 public class Base { public Base() { // 通过反射获取Base类的注解 Annotation[] annotations = Base.class.getAnnotations(); System.out.println("Base:" + Arrays.toString(annotations)); } } public class Sub extends Base { public Sub() { Annotation[] annotations = Sub.class.getAnnotations(); Syst em.out.println("Sub:" + Arrays.toString(annotations)); } } // 测试代码 public class AnnotationDemo { public static void main(String[] args) { Base base = new Base(); Sub sub = new Sub(); } }
运行结果如下:
可以看到Sub只继承了注解MyAnno1,并未继承注解MyAnno2(另Base打印了两行,应当是Sub构造函数隐式调用了父类的无参构造函数引起的)。
@Repeatable
:JDK1.8新加入,标识某个注解可以在同一个声明上多次使用。
自定义注解
[访问修饰符] @interface 注解类名{
// 接口方法,默认为public abstract
int value() default 1;
}
注解使用
如果无法读取注解信息,那注解不会比注释更有用。通过Java反射机制,我们可以读取注解信息,示例如下:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Profile {
int id();
String name();
}
public class AnnotationDemo {
@Profile(id = 1, name = "Tom")
private String field;
public static void main(String[] args) {
Field field = null;
try {
field = AnnotationDemo.class.getDeclaredField("field");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
assert field != null;
Profile profile = field.getAnnotation(Profile.class);
System.out.println("id:" + profile.id() + ",name:" + profile.name());
}
}
运行结果如下: