1,什么是注解
从宏观上讲:注解能够理解为是一个标签,做用在package、class、constructor、field、method之上,代表该元素具备的一类信息。
从代码上讲:@Xxx就是一个注解,使用@interface做用在class名上能够代表该class文件是一个注解类。java
2,注解的表示
java.lang.annotation.Annotation
是一个特殊的接口ide
package java.lang.annotation; public interface Annotation { boolean equals(Object obj); int hashCode(); String toString(); Class<? extends Annotation> annotationType(); }
这4个接口能够认为是JVM运行须要使用的,由编译器在编译期完成,开发人员不须要关注。
使用@interface做用在class名上后即表示该class实现了Annatation接口,具体的实现过程有编译器完成。工具
3,注解的详细表示
先来一个普通的自定义注解:ui
@Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String value(); String name() default "Lily"; }
4,什么是元注解
元注解也是注解,使用来修饰注解的注解,代表该注解的一些基本信息。JDK自带的元注解有: @Inherited、@Retention、@Target、@Repeatable、@Deprecated、@Documented、@SuppressWarnings、@Override等this
@Deprecated用来表示该元素已通过时,再也不推荐使用:code
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated { }
@Documented用来生成Java doc注释:对象
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented { }
@Inherited用来表示被该注解修饰的注解具备继承性。即若是父类有此注解则子类也有此注解继承
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Inherited { }
@Retention用来表示该注解修饰的注解的做用域。接口
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value(); }
@Repeatable表示一个类上能够有多个被该注解修饰的注解,JDK1.8新增作用域
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Repeatable { Class<? extends Annotation> value(); }
@Target表示该注解的能够修饰哪些元素
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
@SuppressWarnings用来表示警告
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); }
@Override用来表示方法重写
@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
@Retention中须要的RetentionPolicy 的源码:
package java.lang.annotation; public enum RetentionPolicy { SOURCE, // 存在于源码中,编译后的class文件中不包含该注解信息。 CLASS, // 该注解会存在于编译后的class文件中,可是JVM运行时不读取该信息。是默认的行为 RUNTIME // 该注解会存在于编译后的class文件中,在JVM运行时会读取该信息,使用反射能够获取到 }
@Target中须要的ElementType的源码:
package java.lang.annotation; public enum ElementType { TYPE, // 类型信息,能够是Class、interface(包括注解类型)、枚举类 FIELD, // 类的属性,包括枚举类型的属性 METHOD, // 方法 PARAMETER, // 方法参数 CONSTRUCTOR, // 构造方法 LOCAL_VARIABLE, // 局部变量 ANNOTATION_TYPE, // 注释 PACKAGE, // 包 TYPE_PARAMETER, // 泛型,JDK1.8新增 TYPE_USE // 任何使用到对象的地方,JDK1.8新增 }
5,注解的使用
由以上分析可知,元注解中对注解开发来讲最重要的是@Target和@Retention。
@Target代表注解修饰的元素类型,@Retention表示注解的使用期。
@Retention中,RetentionPolicy.SOURCE
能够用来开发一些编译器的警告提示之类,通常不用。
RetentionPolicy.CLASS
能够将信息写到class文件中但又在JVM中不使用,须要配合字节码工具使用,通常不用。
RetentionPolicy.RUNTIME
是常常使用的,在运行期反射获得注解信息。
6,注解反射的API
反射中常常使用的是Class、Constructor、Field、Method、Packge都是直接过间接实现了AnnotatedElement接口来读取注解信息。写反射的文章中也提到过。
AnnotatedElement的源码:
package java.lang.reflect; public interface AnnotatedElement { // 该元素上是否有制定类型的注解 default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { return getAnnotation(annotationClass) != null; } // 获取元素上指定类型的注解 <T extends Annotation> T getAnnotation(Class<T> annotationClass); // 获取元素上的全部注解 Annotation[] getAnnotations(); // 获取元素本身的全部注解,不包括继承来的 Annotation[] getDeclaredAnnotations(); // 配合@Repeatable注解使用 default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) { T[] result = getDeclaredAnnotationsByType(annotationClass); if (result.length == 0 && this instanceof Class && AnnotationType.getInstance(annotationClass).isInherited()) { Class<?> superClass = ((Class<?>) this).getSuperclass(); if (superClass != null) { result = superClass.getAnnotationsByType(annotationClass); } } return result; } // 获取元素的指定类型的注解,不包括继承来的 default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) { Objects.requireNonNull(annotationClass); for (Annotation annotation : getDeclaredAnnotations()) { if (annotationClass.equals(annotation.annotationType())) { // More robust to do a dynamic cast at runtime instead // of compile-time only. return annotationClass.cast(annotation); } } return null; } // 配合@Repeatable注解使用 default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) { Objects.requireNonNull(annotationClass); return AnnotationSupport. getDirectlyAndIndirectlyPresent(Arrays.stream(getDeclaredAnnotations()). collect(Collectors.toMap(Annotation::annotationType, Function.identity(), ((first,second) -> first), LinkedHashMap::new)), annotationClass); } }
注意:
注解的继承@Inherited是针对类的,只对类的继承有效果,方法的重写是继承不了的。
参考资料: