概述
Annotation是JDK 5.0以后提供对元数据的支持,可以在编译、加载和运行时被读取,并执行相应的处理。所谓Annotation就是提供了一种为程序元素设置元数据的方法,可用于修饰包、类、构造器、方法、成员变量、参数和局部变量的声明,这些信息被存储在Annotation的“name=value”对中。
Annotation能被用来为程序元素设置元数据,比如一段代码的作者或者告诉编译器禁止一些特殊的错误,不会影响代码的执行。
使用Annotation时要在其前面增加【@】符号,并把该Annotation当作一个修饰符使用,用于修饰它支持的程序元素。
定义一个Annotation类型使用【@interface】关键字,定义一个Annotation类型与定义一个接口非常像(只是多了一个@符号)。
public @interface TestAnnotation {
}
注解的属性
Annotation可以是上面的简单形式,还可以包含成员变量。
Annotation的成员变量以无形参的方法形式来声明,其方法名和返回值定义了该成员变量的名字和类型。
使用带有属性的Annotation时,必须为其属性指定值,否则会报错。
定义Annotation时可以使用【default】关键字为属性设置默认值,使用时可以不为该属性指定值(此时使用默认值)。
如果Annotation中具有名为【value】的属性,在使用时如果只使用value属性的话,可以不写属性名直接指定值。
Annotation的属性类型只能是基本类型、String、Enum、Class及上述类型的一维数组类型。
public class Test {
@UserInfo(password = "123456", value = "这里不能省略")
public static void main(String[] args) {
}
}
@interface UserInfo {
String username() default "bqt";
String password();
String value();
} public class Test {
@UserInfo({ "这里", "可以", "省略", "呵呵" })
public static void main(String[] args) {
}
}
@interface UserInfo {
String username() default "bqt";
String[] value();
} 4个元注解
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它annotation类型作说明。
Java5.0定义的元注解:
- @Target
- @Retention
- @Documented
- @Inherited
这些类型和它们所支持的类在java.lang.annotation包中可以找到。
![](https://images2015.cnblogs.com/blog/795730/201609/795730-20160902175509902-1353480534.png)
@Target注解
@Target修饰普通的Annotation,指定该Annotation可以用于修饰哪些程序单元,例如方法、成员变量等。
作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
@Target注解包含一个ElementType类型的value属性,该属性值只能是如下几个:
- ANNOTATION_TYPE 注释类型声明
- CONSTRUCTOR 构造方法声明
- FIELD 字段声明(包括枚举常量)
- LOCAL_VARIABLE 局部变量声明
- METHOD 方法声明
- PACKAGE 包声明
- PARAMETER 参数声明
- TYPE 类、接口(包括注释类型)或枚举声明
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
public enum ElementType {
TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE
} @Retention注解
@Retention修饰普通Annotation,用于指定Annotation的生命周期。
@Retention包含一个RetentionPolicy类型的value属性,该属性值只能是如下几个:
- CLASS:编译器将把Annotation记录在class文件中。当运行Java程序时,JVM不可获取Annotation信息。
- RUNTIME:编译器将把Annotation记录在class文件中。当运行Java程序时,JVM也可以获取Annotation信息,程序可以通过反射获取该Annotation信息。
- SOURCE:Annotation只保留在源代码中,编译器直接丢弃这种Annotation。
简单来说,就是
- SOURCE:在源文件中有效
- CLASS:在class文件中有效
- RUNTIME:在运行时有效
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
public enum RetentionPolicy {
SOURCE, CLASS, RUNTIME
} @Documented和@Inherited注解
@Documented 用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。
@ Documented是一个标记注解,没有成员。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
} @Inherited也 是一个标记注解,阐述了某个被标注的类型是被继承的。
如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
注意:@Inherited类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。
当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
} 3个基本的注解
在java.lang包中提供了3个基本Annotation的用法,可以通过查看API文档来了解。
![](https://images2015.cnblogs.com/blog/795730/201609/795730-20160902175510324-2034315710.png)
1、@Override:限定重写父类方法。值得注意的是,@Override只能修饰方法,不能修饰其他程序元素。
@Target (ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
} 2、@Deprecated:标示已过时,用于表示某个程序元素已过时,当其他程序使用已过时的类、方法时,编译器将会给出警告。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
} 3、@SuppressWarnings:抑制编译器警告,表示被该Annotation修饰的代码取消显示指定的编译器警告。
@Target ({ TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
} 获取注解信息
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
// 属性
String name();
String[] jobs();
String addr() default "广州";
} public class Person {
@MyAnno(jobs = { "码农", "架构师" }, name = "白乾涛")
public int age = 26;
@MyAnno(jobs = "工作", name = "包青天")
private void fun() {
System.out.println("方法");
}
} public class Test {
public static void main(String[] args) throws Exception {
//1 获取对应类的Class类对象
Class<Person> clazz = Person.class;
//2 根据Class类对象获取Method或Field
Field field = clazz.getField("age");
Method method = clazz.getDeclaredMethod("fun");
//3 通过Class类对象、Metod对象、Field对象,获取对应的注解信息.
MyAnno myAnno1 = field.getAnnotation(MyAnno.class);
MyAnno myAnno2 = method.getAnnotation(MyAnno.class);
System.out.println(Arrays.toString(myAnno1.jobs()));
System.out.println(myAnno2.name());
}
}