java annotation

1. 主要作用

  1. 編譯期檢查

@SuppressWarnings, @Deprecated 和 @Override 都具有編譯檢查作用。

  1. 結合反射,實現更多運行時特性

框架實現中經常使用的方法。

  1. 生成幫助文檔

通過給 Annotation 註解加上 @Documented 標籤,能使該 Annotation 標籤出現在 javadoc 中。

2. 主要組成部分

package java.lang.annotation;
public interface Annotation {

    boolean equals(Object obj);

    int hashCode();

    String toString();

    Class<? extends Annotation> annotationType(); /* 返回Annotation 對應的真實 class 對象  */
}
package java.lang.annotation;
public enum RetentionPolicy {
    SOURCE,            /* Annotation信息僅存在於編譯器處理期間,編譯器處理完之後就沒有該Annotation信息了  */

    CLASS,             /* 編譯器將Annotation存儲於類對應的.class文件中。默認行爲  */

    RUNTIME            /* 編譯器將Annotation存儲於class文件中,並且可由JVM讀入 */
}

每個 annotation 都唯一對應一個 RetentionPolicy(保留策略)。使用元註解 @Retention 來指定。

package java.lang.annotation;

public enum ElementType {
    TYPE,               /* 類、接口(包括註釋類型)或枚舉聲明  */

    FIELD,              /* 字段聲明(包括枚舉常量)  */

    METHOD,             /* 方法聲明  */

    PARAMETER,          /* 參數聲明  */

    CONSTRUCTOR,        /* 構造方法聲明  */

    LOCAL_VARIABLE,     /* 局部變量聲明  */

    ANNOTATION_TYPE,    /* 註釋類型聲明  */

    PACKAGE             /* 包聲明  */
}

每個 annotation 對應 1~N 個 ElementType。使用元註解 @Target 來指定,如果不指定則可以作用於以上所有域中。

3. 兩個特性

兩個特性都是針對 RUNNTIME 保留策略而言的。

3.1 傳遞性

所謂傳遞性,並非語言級特級,但在 spring 中大量應用。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {

	String value() default "";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {

	@AliasFor(annotation = Component.class)
	String value() default "";
	
	boolean proxyBeanMethods() default true;

}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({WebMvcSecurityConfiguration.class})
@EnableGlobalAuthentication
@Configuration
@Deprecated
public @interface EnableWebMvcSecurity {
}

如上:@EnableWebMvcSecurity@Configuration 標註; @Configuration 又被 @Component 標註。
所謂傳遞性其實是通過遞歸解析出來的。

示例:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface FirstLevel {
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@FirstLevel 
public @interface SecondLevel {
}
@SecondLevel
public class TransitivityTest {

    public static void main(String[] args) {
        Set<Annotation> set = new HashSet<>();
        Set<Annotation> allAnnotation = getAllAnnotation(TransitivityTest.class, set);
        for (Annotation annotation : allAnnotation) {
            System.out.println(annotation.annotationType().getName());
        }
    }

    public static Set<Annotation> getAllAnnotation(AnnotatedElement element, Set<Annotation> set) {
        // 獲取當前元素上的 annotations
        Annotation[] declaredAnnotations = element.getDeclaredAnnotations();

        for (Annotation annotation : declaredAnnotations) {
            // 找出 非內置的 annotation, 進行遞歸解析
            if (annotation != null && annotation.annotationType() != null && !annotation.annotationType().getName().startsWith("java.lang.annotation") && set.add(annotation)) { //  visited性能優化用。
                getAllAnnotation(annotation.annotationType(), set);
            }
        }
        return set;
    }
}


輸出結果:
com.yjh.study.annotation.SecondLevel
com.yjh.study.annotation.FirstLevel

3.2 繼承性

繼承性指的是:當交類 Parent 被 Annotation 標註後,其子類不用再顯示用 Annotation 標註,但是可以使用 Annotation 所帶來的特性。

繼承性只有 Annotation 被 @Inherited 標註後,才能生效。

示例:

沒有使用 @Inherited

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@FirstLevel
//@Inherited
public @interface SecondLevel {
}

public class ExtendTest {

    @SecondLevel
    private static class Parent {

    }

    private static class Child extends Parent {

    }

    public static void main(String[] args) {
        Class<Parent> parentClass = Parent.class;
        System.out.println("父類被標註 :" + parentClass.isAnnotationPresent(SecondLevel.class));
        Class<Child> childClass = Child.class;
        System.out.println("子類被標註 :" + childClass.isAnnotationPresent(SecondLevel.class));

    }
}

輸出結果:
父類被標註 :true
子類被標註 :false

使用 @Inherited 後

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@FirstLevel
@Inherited
public @interface SecondLevel {
}

public class ExtendTest {

    @SecondLevel
    private static class Parent {

    }

    private static class Child extends Parent {

    }

    public static void main(String[] args) {
        Class<Parent> parentClass = Parent.class;
        System.out.println("父類被標註 :" + parentClass.isAnnotationPresent(SecondLevel.class));
        Class<Child> childClass = Child.class;
        System.out.println("子類被標註 :" + childClass.isAnnotationPresent(SecondLevel.class));

    }
}

輸出結果:
父類被標註 :true
子類被標註 :true
發佈了64 篇原創文章 · 獲贊 6 · 訪問量 9046
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章