看到一篇总结的不错的文章:
转载: 深入理解Java注解
1.@Target
@Target – 表示该注解用于什么地方,枚举类型ElementType 表示@Target作用位置
@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, // 包
TYPE_PARAMETER,
TYPE_USE
}
@Target的使用:
@Target只有一个方法,默认为value(),返回一个ElementType类型数组
所以使用时既可以带参数名,也可以不带参数名,参数为数组用花括号表示
1. @Target(ElementType.ANNOTATION_TYPE)
2. @Target(value = {ElementType.TYPE})
3. @Target({}) // 不能用来注解任何东西
4. @Target(value = {ElementType.TYPE,ElementType.METHOD})
2.@Retention
@Retention – 定义该注解的生命周期
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE, // 仅出现在源代码中,在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
CLASS, // 被编译在class文件中,但在运行时不需要由JVM保留。在字节码文件的处理中有用。注解默认使用这种方式
RUNTIME // 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式
}
@Retention的使用:
@Retention只有一个方法,返回RetentionPolicy类型,所以直接这样使用
@Retention(RetentionPolicy.RUNTIME)
3.@Documented
@Documented是一个标记注解,没有方法,用于描述其它类型的annotation应该被作为被标注的程序成员的公共API
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
4.@Inherited
@Inherited是一个标记注解,没有方法,是否允许子类继承该注解
如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
5.JDK8 @Repeatable
1.8之前的 JDK 并不允许开发者在同一个声明式前加注同样的 Annotation,(即使属性值不同)这样的代码在编译过程中会提示错误。而 Java 8 解除了这一限制,提供了@Repeattable注解:
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
Class<? extends Annotation> value();
}
- @Repeatable参数为:类名.class
- @Repeatable(c.class)作用在注解annotation上,注解annotation就可以重复标注
/**
* UserRoles中必须定义返回数组类型的 value 方法
* 数组中元素的类型必须为对应的 Repeating Annotation 类型
* */
public @interface UserRoles {
UserRole[] value();
}
/**
* @Repeatable 标签后括号中的值即为指定的Annotation 的类型
* Java编译器会把重复的UserRole对象保存到UserRoles中
* */
@Repeatable(UserRoles.class)
public @interfa UserRole {
String role();
}
/**
* 一个人有多种角色:
* 1.父母的儿子
* 2.老师的学生
* */
@UserRole(role="son")
@UserRole(role="student")
public class User {
}
6.自定义注解
注解定义格式:
public @interface 注解名 {定义体}
定义一个注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Todo {
public enum Priority {LOW, MEDIUM, HIGH}
public enum Status {STARTED, NOT_STARTED}
//定义属性
String value() default "";
Priority priority() default Priority.LOW;
Status status() default Status.NOT_STARTED;
}
- 注解只有方法,没有成员,方法必须是public的,去掉public,默认也是public,因为注解也是一个接口interface
- 注解方法必须有返回类型:返回值类型只能是基本类型、Class、String、enum
- 注解方法运行提供默认值,但不是必需的
- 一个注解方法其实就是一个参数,方法名就是参数名
- 当注解没有方法时,即没有参数,表示一个标记注解
- 当注解有一个方法时,即一个参数,最好把方法名改为“value”,这是默认的
- 当使用自定义的注解时,参数类型可能是基本类型、Class、String、enum或者数组,如果是数组,通过paramname={value1,value2}传入
使用自定义注解:
如果注解中只有一个方法,即一个参数,可以直接命名为“value”,使用时无需再标明属性名
@interface Author {
String value();
}
@Author("lipingan")
public void someMethod() {
}
如果注解方法返回类型(参数类型)为数组,格式如@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface Order {
int value() default 1234;
}
如果注解中有多个方法,即使用时有多个参数,格式为 参数名=参数值
@Todo(priority = Todo.Priority.MEDIUM, author = "李平安", status = Todo.Status.STARTED)
public void testAnnotation() {
//其他代码
}
7.注解处理器类库
定义了注解,并在需要的时候给相关类,类属性加上注解信息,如果没有响应注解信息处理流程,注解可以说是没有实用价值。如何让注解真真的发挥作用,主要就在于注解处理方法,Java SE5扩展了反射机制的API,以帮助快速的构造自定义注解处理器
Java在java.lang.reflect 包下新增了AnnotatedElement接口,该接口代表程序中可以接受注解的程序元素
java.lang.reflect.AnnotatedElement
该接口主要有如下几个实现类:
Class:类定义
Constructor:构造器定义
Field:累的成员变量定义
Method:类的方法定义
Package:类的包定义
当一个Annotation类型被定义为运行时的Annotation后,该注解才能是运行时可见,AnnotatedElement 接口的实现(Class、Method和Constructor)通过Annotation接口的四个方法可以获取该实现上的注解信息