在JDK1.5版本的发布中,Java开始支持注解(java.lang.annotation.Annotation)。
Annotation主要是用来描述并标记类、变量、方法、参数的,不影响被注解的类功能,但是对处理注解的工具有意义,通常可以在编译期使用预编译工具进行处理,也可以在运行期使用Java反射机制进行处理。
学习Annotation之前需要掌握Annotation的生命周期及常用的JDK自带的注解(这些被称为元注解的注解用来描述自定义注解):
JDK自带的注解(只列举2个核心注解) JDK自带的注解 参数 枚举值 说明java.lang.annotation.Retention java.lang.annotation.RetentionPolicy RetentionPolicy.SOURCE
只保留在.java源文件里,对编译工具有帮助意义;
在被编译成.class字节码文件过程中将会被丢弃;
RetentionPolicy.CLASS
只保留在.class字节码文件里,对ClassLoader有帮助意义;
在被ClassLoader加载到JVM过程中将会被丢弃;
RetentionPolicy.RUNTIME
一直保留在JVM中运行,一般用来反射识别实现功能;
自定义注解经常使用;
java.lang.annotation.Target java.lang.annotation.ElementType ElementType.TYPE 可用于类、接口(包括自定义注解)、枚举
ElementType.FIELD 可用于类的属性、枚举中定义的常量
ElementType.METHOD 可用于方法
ElementType.PARAMETER 可用于方法参数
ElementType.CONSTRUCTOR 可用于构造器
ElementType.LOCAL_VARIABLE
ElementType.ANNOTATION_TYPE
ElementType.PACKAGE
ElementType.TYPE_PARAMETER >=1.8
ElementType.TYPE_USE >=1.8
ElementType.MODULE >=9
自定义注解的示例
@Target({ElementType.FIELD,ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)
public @interface NotNull{ boolean value() default true; }
自定义注解在反射中的使用
Class clazz = obj.getClass();
Filed[] fields = clazz.getFields();
for(Field field : fields){
Annotation annotation = field.getAnnotation(NotNull.class);
if(annotation instanceof NotNull){
//检查字段field值不为空
String name = field.getName();
Object value = field.get(obj);
if(null == value){
throw new IllegaArgumentException("对象属性 " + name + " 不能为空");
} }
}
其它示例,常见于各种开源框架的注解使用,比如基于Spring框架的InitializingBean回调或ContextRefreshedEvent事件监听机制的通过反射过滤出自定义注解标记的元素范围实现一些功能。