通过使用Annotation,可以在不改变原有逻辑的情况下,嵌入一些补充的信息。
Annotation 只有成员变量,没有方法,成员变量以无参的方法来定义,方法名为成员变量名,方法的返回值为成员变量的类型。java.lang.annotation.Annotation接口:这个接口是所有Annotation类型的父接口。
根据是否包含成员变量可将 分为两类:
标记Annotation:没有成员变量,仅用自身存在与否来提供信息,比如@Override注解元数据Annotation:有成员变量,因为它们可以接受更多的元数据,因此被称为元数据Annotation。1) @Retention 指定Annotation可以保留多长时间 举个栗子~:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { // 该value成员变量是RetentionPolicy枚举类型 // RetentionPolicy.SOURCE:Annotation只保留在源代码中,编译器编译时,直接丢弃这种Annotation。 // RetentionPolicy.CLASS:编译器把Annotation记录在class文件中。当运行Java程序时,JVM中不再保留该Annotation。 // RetentionPolicy.RUNTIME:编译器把Annotation记录在class文件中。当运行Java程序时,JVM会保留该Annotation,程序可以通过反射获取该Annotation的信息。 RetentionPolicy value(); }2) @Target 指定Annotation用于修饰哪些程序元素(包、类、构造器、方法、成员变量、参数、局域变量),用于指明被修饰的注解最终可以作用的目标是谁,也就是指明,你的注解到底是用来修饰方法的?修饰类的?还是用来修饰字段属性的。 举个栗子~:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { // 该value成员变量是ElementType型数组,ElementType为枚举类型 // ElementType.TYPE:能修饰类、接口或枚举类型 // ElementType.FIELD:能修饰成员变量 // ElementType.METHOD:能修饰方法 // ElementType.PARAMETER:能修饰参数 // ElementType.CONSTRUCTOR:能修饰构造器 // ElementType.LOCAL_VARIABLE:能修饰局部变量 // ElementType.ANNOTATION_TYPE:能修饰注解 // ElementType.PACKAGE:能修饰包 ElementType[] value(); }3) @Documented 如果定义注解A时,使用了@Documented修饰定义,则在用javadoc命令生成API文档后,所有使用注解A修饰的程序元素,将会包含注解A的说明。 当我们执行 JavaDoc 文档打包时会被保存进 doc 文档,反之将在打包时丢弃。
举个栗子~:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented {}4) @Inherited 是否允许子类继承该注解,指定的具有继承性,也就说我们的注解修饰了一个类,而该类的子类将自动继承父类的该注解。 举个栗子~:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Inherited {} @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.METHOD}) @Documented @Inherited public @interface MyAnnotation { // 在定义成员变量是可以指定默认值 String name() default "zm"; int age() default 18; } public class Test { // 可以在使用注解时设置成员变量值 @MyAnnotation(name="ok", age=24) public void info { ... } } @MyAnnotation public class BaseClass { } // 子类继承基类,虽然子类没有用@MyAnnotation注解,但是由于基类有@MyAnnotation注解且@MyAnnotation注解具有继承性(@MyAnnotation使用@Inherited声明),所以子类也有@MyAnnotation注解 public class SubClass extends BaseClass { public static void main(String[] args) { // 输出true System.out.println(SubClass.class.isAnnotationPresent(MyAnnotation.class)); } }1、@Override 它没有任何的属性,所以并不能存储任何其他信息。它只能作用于方法之上,编译结束后将被丢弃。
它就是一种典型的『标记式注解』,仅被编译器可知,编译器在对 java 文件进行编译成字节码的过程中,一旦检测到某个方法上被修饰了该注解,就会去匹对父类中是否具有一个同样方法签名的函数,如果不是,自然不能通过编译。
2、@Deprecated 依然是一种『标记式注解』,永久存在,可以修饰所有的类型,作用是,标记当前的类或者方法或者字段等已经不再被推荐使用了,可能下一次的 JDK 版本就会删除。
3、@SuppressWarnings 主要用来压制 java 的警告
一个栗子~
另一个栗子:提取方法上的@MyAnnotation注解的成员变量信息
public class Demo { public void m1() {} @MyAnnotation // 都是默认值时可以把括号省略 public void m2() {} @MyAnnotation(name="ok") pubic void m3() {} @MyAnnotation(age="24") public void m4() {} @MyAnnotation(name="ok", age=24) public void m5() {} } public class Test { public static void main(String[] args) { processTool("com.zm.Demo"); } public static void processTool(String className) { Class clazz = null; try { clazz = Class.forName(className); } catch(ClassNotFoundException e) { e.printStackTrace(); } if (clazz != null) { for (Method m : clazz.getMethods()) { if (m.isAnnotationPresent(MyAnnotation.class)) { MyAnnotation myAnnotation = m.getAnnotation(MyAnnotation.class); System.out.println("方法" + m.getName() + "的MyAnnotation注解信息为:" + myAnnotation.name() + " " + myAnnotation.age()); } } } } } // 输出 方法m2的MyAnnotation注解信息为:zm 18 方法m3的MyAnnotation注解信息为:ok 18 方法m4的MyAnnotation注解信息为:zm 24 方法m5的MyAnnotation注解信息为:ok 24