註解Annotation學習基礎篇

1.Annotation是什麼?
註解是JDK5新增的,主要爲程序增加元數據。Annotation是一種接 口,主要用來對JAVA應用程序元素設置元數據。需要通過JAVA反射技術獲得Annotation對象,根據Annotation對象實例獲取程序元素上的元數據信息即Annotation信息。
2.如何定義Annotation?
定義註解Annotation很簡單,通過關鍵字@interface即可定義一個註解。下圖自定義一個註解。

        @Documented
        @Target(ElementType.METHOD)
        @Inherited
        @Retention(RetentionPolicy.RUNTIME)
        public @interface MethodInfo {
        // 作者
        String author() default "tonny";
        // 日期
        String date();
        }

3.哪些程序元素可以使用註解?
JAVA應用中哪些程序元素可以使用Annotation。在JDK中另外一個AnnotatedElement接口代表了程序中可以使用Annotation的程序元素,JDK中具體的實現類主要有:
3.1 Class:JAVA類從面可以使用註解Annotation.
3.2. Constructor:構造器可以使用註解Annotation。
3.3. Method:JAVA類中的方法可以使用註解Annotation
3.4. Field:JAVA類中的成員變量可以使用Annotation,Spring中 很多場景。
3.5. Package: 類的包定義上使用註解
4.註解特點
4.1.註解中可以定義方法,但都是無參的方法,即不能有任何參數。
4.2.註解中的方法可以有默認值,必須使用default 賦值。上述中,就是採用default進行賦值
4.3.註解中的方法名和返回類型就是註解中的成員變量名和變量類型
4.4.註解的返回類型只能是基本類型,String,枚舉類型,Annotation類型和這些類型組成的數組–非常重要
4.5.註解中如果定義成員變量,如果成員變量沒有默認值(即沒有使用default進行賦值),則在使用該註解時必須對成員變量進行賦值。
4.6.註解中可以包含元註解,元註解被用來定義自定義註解
5.四個元註解
JDK中提供了4個元數據註解,這4個元註解可以註解自定義註解
5.1@Target:
5.1.1.主要表明使用@Target註解的範圍,可以在哪些應用程序元素中使用。

        @Documented
        @Retention(RetentionPolicy.RUNTIME)
        @Target(ElementType.ANNOTATION_TYPE)
        public @interface Target {
            ElementType[] value();
        }

5.1.2.@Target的註解範圍通過ElementType枚舉類數組指定:

public enum ElementType {
    /** Class, interface (including annotation type), or             enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE
}

5.1.3.上述程序中是元註釋@Target源碼,可以發現@target包含元註解,通過該ElementType.ANNOTATION_TYPE指明瞭註解的範圍。
5.1.4.@Target註解的方法名爲value,即成員變量名。返回類型爲一個枚舉ElementType。符合註解中方法的返回類型要求(枚舉類型或枚舉類型數組)
5.1.5.通常情況下使用註解中的方法時,應該使用”name=value”形式。即 上述程序中@Target(ElementType.ANNOTATION_TYPE)
應該爲@Target(value = ElementType.ANNOTATION_TYPE)。如下情況特殊除外:
5.1.5.1如果自定義的註解中就含有一個成員變量而且成員變量的名稱爲value,則可以不需要使用name=value形式。
5.2@Retention
5.2.1使用@Retention修飾自定義的Annotation,表明該Annotation的聲明週期

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}

5.2.2上述源碼錶明@Retention生命週期通過RetentionPolicy控制。RetentionPolicy爲枚舉類,主要包含3個數值:
5.2.2.1.RetentionPolicy.SOURCE:編譯器直接丟棄這種策略。
5.2.2.2.RetentionPolicy.CLASS:編譯器將Annotation記錄在CLASS文件中,但是JVM在運行時會拋棄。這也是默認行爲
5.2.2.3RetentionPolicy的源碼如下:

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    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.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

5.3@Inherited
5.3.1@Inherited指定被它註解的Annotation將具有繼承性質,如果某 個類使用了自定義註解A(A註解被@Inherited修飾),則A的子類也具有A註解的特性。
5.3.2@Inherited的源碼如下,只是標記註解

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Inherited {
    }

5.4@Documented
5.4.1.@Documented修飾的註解可以被javadoc工具文檔化。也是一個標記註解,源碼如下:

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

6.自定義註解
6.1自定義註解只需要使用@interface聲明即可,如下定義了MethodInfo註解

@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodInfo {
    // 作者
    String author() default "tonny";
    // 日期
    String date();
    // 版本
    int version() default 1;
    // 註釋
    String comments();
}

6.2.定義了AnnotationExample類,使用自定義註解,如下

public class AnnotationExample {

    @Override
    @MethodInfo(author="tonny",date="2016-08-11",comments="override toString method")
    public String toString(){
        return "Override toString method";
    }
    @Deprecated
    @MethodInfo(date="2016-08-11",comments="deprecated method")
    public void oldMethod(){
        System.out.println("deprecated method do not use it");
    }

    @SuppressWarnings(value = { "unchecked" })
    @MethodInfo(date="2016-08-11",comments="deprecated method")
    public List generateList(){
        List l = new ArrayList();
        l.add("a");
        l.add("b");
        return l;
    }
}

6.3.類AnnotationParse.java是一個簡單的解析註解的小程序:

public class AnnotationParse {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            Method[] methods = AnnotationParse.class.getClassLoader()
            .loadClass("com.egfbank.annotaion.example1.AnnotationExample")
            .getMethods();
            for(Method m:methods){
                // getAnnotations()返回指定元素上所有的註釋
                for(Annotation anno : m.getAnnotations()){
                    System.out.println("annotation : "+anno); 
                }            
                //檢查 註解MethodInfo是否起到作用
                // 判斷程序中指定元素上某個特定的註釋是否存在
                if(m.isAnnotationPresent(MethodInfo.class)){
                    MethodInfo ma =  m.getAnnotation(MethodInfo.class);
                    System.out.println(ma.author());
                    System.out.println(ma.date());
                }
            }
        }catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

7.總結
7.1通過上述例子,可以看出註解必須和反射技術結合起來才能發揮重要的作用。靈活使用註解可以減少很多無用的代碼的編寫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章