我所理解的JDK註解

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";
}
  • @Documented、@Target、@Retention是JDK自帶的一些元註解。
  • value()是一個註解類的默認方法,使用@MyAnnotation("abc")時在括號內不須要指定value,就表示value="abc"
  • default表示默認值,@MyAnnotation("abc", name="Lucy")則表示value="abc",name="Lucy"。若是沒有指定name,則name="Lily"
  • 若是沒有默認值時,使用註解時必須指定值,不然報錯。好比@MyAnnotation()就會提示錯誤,須要指定value

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

參考資料:

  1. 以上內容爲筆者平常瑣屑積累,已無從考究引用。若是有,請站內信提示。
相關文章
相關標籤/搜索