定义
- 也叫作元数据。一种代码级别的说明。他是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以生命在包、类、字段、方法、局部变量、方法参数等的前面,用于对这些元素进行说明,注释。
作用的分类
- 编写文档:通过代码里标识的元数据生成文档
- 代码分析:通过代码里标识的元数据对代码进行分析
- 编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查
如何定义一个注解
示例如下
}
一、可以为其添加相应的参数,参数的定义为:【类型 参数名称() default 属性值】或者【类型 参数名称()】。如果没有为参数定义默认值,则使用该注解时,此参数为必填项。
@interface Style{ String background() default "blue"; //设置默认值 int fontSize() ; //没有设置默认值,则使用本注解时,该参数必填 String[] padding() default {"0"}; enum Color{ BULE,RED,GREEN}; boolean gnore() default false; } @Style(fontSize=1) class Table{ } public class ZhujieTest { public static void main(String[] args) { Method m; try { //获取方法上的注解。获取字段、类的注解的方式和获取方式的注解方式类似。 m = Table.class.getMethod("a",null); System.out.println(m); System.out.println(m.getDeclaredAnnotations().length); System.out.println(m.getAnnotations().length); System.out.println(m.getAnnotation(Style.class));//获取指定的注解 } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
注解参数可以支持的数据类型:
- 所有的基本类型(int,float,boolean,byte,double,char,long,short)
- String类型
- Class类型
- enum类型
- Annoatation类型
- 以上所有类型的数组
注:基本类型的包装类也不支持。
二、4个标准的meta-annotation类型,它们被用来提供对其他annotation类型作说明。它们分别是
- @Target 用来说明注解所修饰的对象范围
- @Retention 定义了该注解所保留的时间长短
- @Documented 用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化
- @Inherited 元注解的一个标记注解。该是否能被子类所继承。
@Target,若未使用添加该注解,则使用位置不受限制。其取值(ElementType)如下:
CONSTRUCTOR | 用于描述构造器 |
FIELD | 用于描述域 |
LOCAL_VARIABLE | 用于描述局部变量 |
METHOD | 用于描述方法 |
PACKAGE | 用于描述包 |
PARAMETER | 用于描述参数 |
TYPE | 用于描述类、接口(包括注解类型) 或enum声明 |
@Retention,被描述的注解在什么范围内失效。其取值(RetentionPoicy)如下
SOURCE | 在源文件中有效(即源文件保留) |
CLASS | 在class文件中有效(即class保留) |
RUNTIME | 在运行时有效(即运行时保留) |
其关系:RUNTIME 包含CLASS,CLASS 包含SOURCE。
注:若不添加该注解,则默认是保留在class文件内有效。只有设置为RUNTIME,才能通过反射获取到。
@Documented
用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
@Inherited
是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。
当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
总结:若希望通过反射获取注解,请添加 @Retention(RetentionPolicy.RUNTIME);
若希望指定注解的使用范围,请使用注解@Target,后面指定范围属性;
若希望类的注解能被子类应用,则使用@Inherited ;方法的注解重载后不能被继承。
若参数只有一个,则可以将参数名称设置为value;在使用该注解时,参数名称可以忽略不写。如下示例:
@interface V{ String value(); } @interface V2{ String val(); } @V("") //可以忽略参数名 @V2(val="") //参数名必填 class CV{ @V(value ="") public void v1(){} }