注解为程序提供元数据(metadata).元数据又称中介数据、中继数据,为描述数据的数据(data about data),主要是描述数据属性(property)的信息。它不会影响程序的编译方式,也不会影响最终的编译结果。
注解可以提供更大的便捷性,易于维护修改,但耦合度高,而 XML 相对于注解则是相反的。
注解使用场景如下
注解格式
1 2 @SuppressWarnings(value = "unchecked") void myMethod() { ... }
注解使用场景
类实例创建
1 new @annotation myobject()
类型投射
1 myString = (@NonNull String) str;
实现条款
1 2 class UnmodifiableList<T> implements @Readonly List<@Readonly T> { ... }
抛出异常声明
1 void testfunc() throws @annotation exception{}
注解的声明 一个简单的注解声明
1 2 3 4 @interface anno{ String name(); Interger age() default 18; }
注解的声明,就像在 interface 声明前面添加一个@字符(@是AT,即 Annotation Type)。注解类型,其实是接口的一种特殊形式
使用注解
使用时,填充注解的值就好了
1 2 3 4 5 6 7 @anno( name="swiftr", age=18, ) class testclass{ }
注解应用于其他注解 注解应用于其他注解称为元注解 java.lang.annotation中也定义了很多元注解 @Retention 注解指定了标记的注解如何存储
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public enum RetentionPolicy { /** * Annotations are to be discarded by the compiler. *保留在源码级,在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override、@SuppressWarnings都属于这类注解 */ SOURCE, /** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior.该标记注释是由编译器在编译时保留, 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。 */ CLASS, /** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, so they may be read reflectively. *该标记注解由JVM保留,因此可以使用在运行时环境。因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。 * @see java.lang.reflect.AnnotatedElement */ RUNTIME }
@Target 用于标记其他注解,限制什么样的 Java 元素的注解可以应用到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 /** Class, interface (including annotation type), or enum declaration */ TYPE, /** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Formal parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE, /** * Type parameter declaration * * @since 1.8 */ TYPE_PARAMETER, /** * Use of a type * * @since 1.8 */ TYPE_USE
@Inherited 指示注释类型可以从超类继承。(默认不是 true)。当用户查询注释类型,类没有这种类型注释,此时从这个类的父类中查询注释类型。这个注释只适用于类的声明。
@Repeatable注解,在 Java SE 8 中引入的,表示该标记的注解可以多次应用到同一声明或类型使用。
类型注解 例如,确保在你的程序中一个特定变量从未被分配到 null可以这样写
重复注解 注解包含相同的类型,则被称为重复注解
重复的注释被存储在一个由 Java 编译器自动产生的容器注解(container annotation)里。为了使编译器要做到这一点,你的代码里两个声明都需要。
1 2 3 @Schedule(dayOfMonth="last") @Schedule(dayOfWeek="Fri", hour="23") public void doPeriodicCleanup() { ... }
声明一个重复注解
1 2 3 4 5 6 @Repeatable(Schedules.class) public @interface Schedule { String dayOfMonth() default "first"; String dayOfWeek() default "Mon"; int hour() default 12; }
@Repeatable的值是由java编译器生生成储存重复注解的容器
声明容器注解类型
1 2 3 public @interface Schedules { Schedule[] value(); }
该注解的值为重复注解的数组类型
示例 下面是注解一个简单的应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class classtest { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { AnnotationTest test = new AnnotationTest(); test.execute(); //获取Annotation 的class实例 Class<AnnotationTest> cl = AnnotationTest.class; //获取Method实例 Method method = cl.getMethod("execute",new Class[]{}); //判断是否包含myAnnotation注解 if (method.isAnnotationPresent(myAnnotation.class)){ //获取改方法注解实例 myAnnotation my = method.getAnnotation(myAnnotation.class); //执行该方法 method.invoke(test,new Object[]{}); //获取注解的属性值 String name = my.name(); System.out.println(name); } //获取方法上的所有注解 Annotation[] annotations = method.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } } } @Documented @Retention(RetentionPolicy.RUNTIME) @interface myAnnotation{ String name() default "swiftr"; } class AnnotationTest { @myAnnotation(name = "https://swiftr.top") public void execute() { System.out.println("do something~"); } }
运行结果
1 2 3 4 5 6 do something~ do something~ https://swiftr.top @cn.lzl.mqdemo.mianshi.注解.myAnnotation(name=https://swiftr.top) Process finished with exit code 0