注解的概念
- 注解(Annotation),也叫元数据(Metadata),是Java5的新特性,JDK5引入了Metadata很容易的就能够调用Annotations。注解与类、接口、枚举在同一个层次,并可以应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中,用来对这些元素进行说明注释。
注解的语法与定义形式
- 以@interface关键字定义
- 注解包含成员,成员以无参数的方法的形式被声明。其方法名和返回值定义了该成员的名字和类型。
- 成员赋值是通过@Annotation(name=value)的形式。
- 注解需要标明注解的生命周期,注解的修饰目标等信息,这些信息是通过元注解实现。
以 java.lang.annotation 中定义的 Target 注解来说明:
1 2 3 4 5
| @Retention(value = RetentionPolicy.RUNTIME) @Target(value = { ElementType.ANNOTATION_TYPE } ) public @interface Target { ElementType[] value(); }
|
源码分析如下:
第一:元注解@Retention,成员value的值为RetentionPolicy.RUNTIME。
第二:元注解@Target,成员value是个数组,用{}形式赋值,值为ElementType.ANNOTATION_TYPE
第三:成员名称为value,类型为ElementType[]
另外,需要注意一下,如果成员名称是value,在赋值过程中可以简写。如果成员类型为数组,但是只赋值一个元素,则也可以简写。如上面的简写形式为:
1 2 3 4 5
| @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
|
注解的分类
注解的分类有两种分法:
- 第一种分法
1)基本内置注解,是指Java自带的几个Annotation,如@Override、Deprecated、@SuppressWarnings等;
2)元注解(meta-annotation),是指负责注解其他注解的注解,JDK 1.5及以后版本定义了4个标准的元注解类型,如下:
- @Target
- @Retention
- @Documented
- @Inherited
3)自定义注解,根据需要可以自定义注解,自定义注解需要用到上面的meta-annotation
- 第二种分法,根据作用域分类
1)源码时注解(RetentionPolicy.SOURCE)
2)编译时注解(RetentionPolicy.CLASS)
3)运行时注解(RetentionPolicy.RUNTIME)
注解需要标明注解的生命周期,这些信息是通过元注解 @Retention 实现,注解的值是 enum 类型的 RetentionPolicy,包括以下几种情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME }
|
元注解
如上所介绍的Java定义了4个标准的元注解:
- @Documented:标记注解,用于描述其它类型的注解应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。
1 2 3 4 5
| @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented { }
|
- @Inherited:标记注解,允许子类继承父类的注解
1 2 3 4 5
| @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Inherited { }
|
- @Retention:指Annotation被保留的时间长短,标明注解的生命周期,3种RetentionPolicy取值含义上面以说明
1 2 3 4 5 6
| @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { RetentionPolicy value(); }
|
- @Target:标明注解的修饰目标,共有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
public enum ElementType { TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE }
|
使用反射API读取注解
- MyAnno自定义注解类
1 2 3 4 5 6 7 8
| @Target({ElementType.TYPE,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnno{ String value() default "猿同学"; String name() default "猿同学"; int id() default -1; int age() default 18; }
|
- POJO类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| @MyAnno("java") public class User { @MyAnno(id=20) private int id; @MyAnno(name="java") private String name; @MyAnno(age=20) private int age;
public User() { }
public User(int id, String name, int age) { this.id = id; this.name = name; this.age = age; }
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
|
- 利用反射读取注解
1 2 3 4 5 6 7 8 9 10
| public class TestAnnoReflat { public static void main(String[] args) throws Exception { Class cls = Class.forName("com.sc.domain.User"); MyAnno annotation = (MyAnno) cls.getDeclaredAnnotation(MyAnno.class); System.out.println(annotation.value());
MyAnno name = cls.getDeclaredField("name").getAnnotation(MyAnno.class); System.out.println(name.name()); } }
|