Annotation(注解)就是Java提供了一种元程序中的元素关联任何信息和着任何元数据(metadata)的途径和方法。Annotion(注解)是一个接口,程序可以通过反射来获取指定程序元素的Annotion对象,然后通过Annotion对象来获取注解里面的元数据。
Annotation能被用来为某个程序元素(类、方法、成员变量等)关联任何的信息。需要注意的是,这里存在着一个基本的规则:Annotation不能影响程序代码的执行,无论增加、删除 Annotation,代码都始终如一的执行。另外,尽管一些annotation通过java的反射api方法在运行时被访问,而java语言解释器在工作时忽略了这些annotation。正是由于java虚拟机忽略了Annotation,导致了annotation类型在代码中是“不起作用”的; 只有通过某种配套的工具才会对annotation类型中的信息进行访问和处理。
三种内置的注解,在java.lang包中:
- @Override
- @Deprecated 表示修饰的内容已经过时了,不建议使用这个方法了。
- @SupressWarnings 关闭不当的编译器警告信息
SupressWarnings 的参数是一个String数组,可以的取值有
1.deprecation:使用了不赞成使用的类或方法时的警告;
2.unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型;
3.fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
4.path:在类路径、源文件路径等中有不存在的路径时的警告;
5.serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
6.finally:任何 finally 子句不能正常完成时的警告;
7.all:关于以上所有情况的警告
public @interface _Test { }
在注解中可以包含一些元素,注解跟接口很相似,但是注解的元素可以指定默认值,没有元素的注解成为标记注解
注解可以定义到任意的位置上,使用的位置可以由@Target指定。
元注解
@Target 表示注解可以用于什么地方 在ElementType中
- CONSTRUCTOR
- FIELD
- LOCAL_VARIABLE
- METHOD
- PACKAGE
- PARAMETER
- TYPE 类、接口、enum、注解的声明
@Retention 表示在什么级别保存注解信息,在RetentionPolicy中
- SOURCE
- CLASS
- RUNTIME
@Documented 将此注解包含在javadoc中
@Inherited 允许子类继承父类的注解,是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。
注解中的元素只能是一下类型,默认值必须是确定的,不能是null:
- 基本类型
- String
- Class
- enum
- Annatation,,也就是注解可以嵌套
注解的一个价值在于,对于RUNTIME的注解,可以通过反射机制来获得注解的信息对应的相关的值,完成相关操作
注解的赋值:
当元素的名字是value的时候,如果只想对这一个元素赋值,可以直接写,不用key=val的对儿
对于数组,使用{}赋值,多个参数使用逗号隔开,并且要使用 key=val的语法
关于反射读取注解:
AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了某个类的AnnotatedElement对象之后,程序就可以调用该对象的如下 四个个方法来访问Annotation信息:
方法1:<T extends Annotation> T getAnnotation(Class<T> annotationClass): 返回改程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。
方法2:Annotation[] getAnnotations():返回该程序元素上存在的所有注解。
方法3:boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.
方法4:Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。
程序举例:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface classIfo{ String value() default ""; } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface NameType{ String value() default "这是乳名"; } @Retention(RetentionPolicy.RUNTIME) @interface adultIfo{ String name() default ""; int age() default 0; } @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface parentIfo{ int Marriage_time() default -1; //这里是注解的嵌套,其实用起来跟一般的类型一样,使用的时候就把注解当成是接口就可以了 adultIfo [] parent() default {}; } @classIfo("学生类-用来测试反射机制读取Annotation") class Student{ //不指定参数就是使用默认值 @NameType String name="小明"; //这里注意数组和嵌套的使用 @parentIfo(Marriage_time=20,parent={@adultIfo(name="baba",age=39),@adultIfo(name="mama",age=39)}) String getParent(){ return "parent"; } } public class Demo04 { public static void main(String[] args){ Class<?> cc=Student.class; Field[] ff=cc.getDeclaredFields(); for(Field f:ff){ if(f.isAnnotationPresent(NameType.class)){ NameType nt=f.getAnnotation(NameType.class); System.out.println("名字类型的说明 "+nt.value()); } } Method[] mm=cc.getDeclaredMethods(); for(Method m:mm){ if(m.isAnnotationPresent(parentIfo.class)){ parentIfo pi=m.getAnnotation(parentIfo.class); System.out.println("结婚时间:"+String.valueOf(pi.Marriage_time())); adultIfo ai[]=pi.parent(); System.out.println("父亲"+ai[0].name()+" "+ai[0].age()); System.out.println("母亲"+ai[1].name()+" "+ai[1].age()); } } } }