一、引言
作为Java开发人员,注解想必大家都不会陌生,在日常的工作,我们也会经常用到注解,java注解是在JDK5开始引入的新特性,它很好简化了代码,解耦程序;本文我将从注解的语法和特性进行总结.
二、注解的语法特性
1. 注解的声明
首先我们来看一个@Test注解的源码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
}
由上的例子,可看到一个注解由三个主要元素组成,@interface,@Retention,@Target,对于@Target
和@Retention
是由Java提供的元注解,所谓元注解就是标记其他注解的注解; 它们的作用如下:
- @interface,声明一个注解,所有的注解都要通过interface来声明
- @Target,声明注解作用的范围,参数ElementType.METHOD,表明该注解只能用在方法上,ElementType的完整定义如下
public enum ElementType {
/**标明该注解可以用于类、接口(包括注解类型)或enum声明*/
TYPE,
/** 标明该注解可以用于字段(域)声明,包括enum实例 */
FIELD,
/** 标明该注解可以用于方法声明 */
METHOD,
/** 标明该注解可以用于参数声明 */
PARAMETER,
/** 标明注解可以用于构造函数声明 */
CONSTRUCTOR,
/** 标明注解可以用于局部变量声明 */
LOCAL_VARIABLE,
/** 标明注解可以用于注解声明(应用于另一个注解上)*/
ANNOTATION_TYPE,
/** 标明注解可以用于包声明 */
PACKAGE,
/**
* 标明注解可以用于类型参数声明(1.8新加入)
* @since 1.8
*/
TYPE_PARAMETER,
/**
* 类型使用声明(1.8新加入)
* @since 1.8
*/
TYPE_USE
}
3. @Retention,约束注解的声明周期,分别是源码级(source),类文件级别(class),运行时级别 (runtime),具体含义如下:
- SOURCE:注解将被编译器丢弃(该类型的注解信息只会保留在源码里,源码经过编译后,注解信息会被丢弃,不会保留在编译好的class文件里)
- CLASS:注解在class文件中可用,但会被VM丢弃(该类型的注解信息会保留在源码里和class文件里,在执行的时候,不会加载到虚拟机中),请注意,当注解未定义Retention值时,默认值是CLASS,如Java内置注解,@Override、@Deprecated、@SuppressWarnning等
- RUNTIME:注解信息将在运行期(JVM)也保留,因此可以通过反射机制读取注解的信息(源码、class文件和执行的时候都有注解的信息),如SpringMvc中的@Controller、@Autowired、@RequestMapping等。
2. 注解元素及其数据类型
很多注解内部是没有定义任何元素,如@Override注解,这种类型的注解称为标记注解(marker annotation),但往往我们需要注解内部定义一些元素,方便提供更强大的功能,如@Controller注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
String value() default ""; //定义了String类型的value元素,默认值为空字符串
}
注解内部元素支持的数据类型
-
所有基本类型(int,float,boolean,byte,double,char,long,short)
-
String
-
Class
-
enum
-
Annotation
-
上述类型的数组
通过代码进一步加深理解
package com.zach.annotation;
public @interface AnnotationDemo {
//String
String value() default "";
//boolean
boolean flag() default false;
//声明枚举类型
Enum status() default Enum.FIXED;
//Class类型
Class<?> myClass() default Void.class;
//嵌套注解
AnnotationReference reference() default @AnnotationReference(next = true);
}
//枚举
enum Enum {FIXED,NORMAL};
//注解
@Target({ElementType.ANNOTATION_TYPE,ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationReference {
boolean next() default false;
}
注意: 编译器对元素的默认值是有严格的限制的
- 元素不能有不确定的值,要么具有默认值,要么在使用时提供元素的值
- 对于非基本数据类型元素,无论是在源代码中声明,还是在注解接口中定义默认值,都不能以null作为值
- 注解不支持继承,不能使用extends来继承某个@interface,但是注解在编译之后会自动继承java.lang.annotation.Annotation接口
故我们可以在设置默认值,以空字符串或负数来表示某个元素不存在