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是針對類的,只對類的繼承有效果,方法的重寫是繼承不了的。
參考資料: