JAVA基礎(chǔ)篇(6)-自定義注解(理論)

JAVA && Spring && SpringBoot2.x — 學習目錄

注解可以代替配置文件的功能。

1. 元注解

元注解的作用就是注解其他注解,一般我們使用自定義注解時,就需要用元注解來標注我們自己的注解,一共有以下四個元注解。

1.1 @Target注解

說明Annotation被修飾的范圍,可被用于packages、type(類,接口,枚舉,Annotation類型)、類型成員(方法,構(gòu)造方法,成員變量,枚舉值)、方法參數(shù)和本地變量(如循環(huán)變量,catch參數(shù))。

一句話總結(jié):定義了注解的作用范圍。
使用方法:@Target(ElementType.TYPE)

類型 作用域
ElementType.CONSTRUCTOR 用于描述構(gòu)造器
ElementType.FIELD 用于描述域(類的成員)
ElementType.LOCAL_VARIABLE 用于描述局部變量(方法內(nèi)部變量)
ElementType.METHOD 用于描述方法
ElementType.PACKAGE 用于描述包
ElementType.PARAMETER 用于描述參數(shù)
ElementType.TYPE 用于描述類、接口(包括注解類型) 或enum聲明

1.2 @Retention

[瑞ten神]定義了該注解被保留的時間長短,有些只在源碼中保留,有些需要編譯成的class中保留,有些需要在程序運行時候保留。

一句話總結(jié):定義注解的聲明周期。
使用方法:@Retention(RetentionPolicy.RUNTIME)

類型 作用域
RetentionPoicy.SOURCE 在源文件中有效(即源文件保留)
RetentionPoicy.CLASS 在class文件中有效(即class保留)
RetentionPoicy.RUNTIME 在運行時有效(即運行時保留)

1.3 Documented

標記注解,該元注解沒有屬性。表明這個注解應該被javadoc工具記錄。即若使用javadoc之類的工具處理,該注解信息會被生成到文檔中。

1.4 Inherited

[in 和 瑞 ti 得]標記注解,被他標記的類型是可繼承的,比如一個class被@Inherited標記,那么一個子類繼承該class后,則這個注解將被用于該class的子類。

自定義注解無@Inherited 自定義注解有@Inherited
子類能否繼承父類上的注解
子類方法,實現(xiàn)了父類的抽象方法,能否可以繼承注解
子類方法,繼承了父類方法,能否繼承注解
子類方法,覆蓋了父類方法,能否繼承注解
@MyAnno
public interface Eat {
}

class Parent implements Eat {

}

class Child implements Eat {

}

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@RequestMapping
@interface MyAnno {


}

class Test {

    public static void main(String[] args) {
        MyAnno eatAnnotation = Eat.class.getAnnotation(MyAnno.class);
        MyAnno parentAnnotation = Parent.class.getAnnotation(MyAnno.class);
        MyAnno childAnnotation = Child.class.getAnnotation(MyAnno.class);
        System.out.println(eatAnnotation);  //@com.galax.common.anno.customAnno.MyAnno()
        System.out.println(parentAnnotation); //null
        System.out.println(childAnnotation); //null
    }
}

我們的注解標注了@Inherited表示該注解可以被繼承,但是parentAnnotation和childAnnotation依舊是null。需要注意:@Inherited繼承只能發(fā)生在類上,而不發(fā)生在接口上(也就是說標注在接口上依舊不能被繼承。)

2. 自定義注解

1. 自定義注解的格式

public @interface 注解名 {定義體}

使用@interface定義的一個注解,自動繼承了java.lang.annotation.Annotation接口,其中的每一個方法實際上是聲明了一個配置參數(shù)。方法的名稱就是參數(shù)的名稱,返回值就是參數(shù)的類型(返回值類型只能是:基本類型、Class、String、enum類型、Annotation類型,以及上述參數(shù)的數(shù)組類型)。可以使用default來聲明參數(shù)的默認值。

2. 需要注意的點:

  1. 只能用public或默認(default)這兩個訪問權(quán)修飾。
  2. 如果只有一個參數(shù)成員,最好把參數(shù)名稱設(shè)為"value"。
  3. 參數(shù)的返回值,只能是基本類型,String類型,Class類型,枚舉類型,注解類型以及他們的數(shù)組類型。

3. 注解的默認值

注解元素必須有確定的值,要么是給定的默認值,要是使用的時候賦予值。需要注意的是:若需要表達一個元素不存在值,所以使用空字符串或者負數(shù)表示某個元素不存在,在定義注解時,這已經(jīng)成為一個約定用法。

3. 如何獲取自定義注解信息

Java自定義注解是通過運行時靠反射獲取注解

AnnotatedElement對象.png
Class上實現(xiàn)AnnotatedElement接口.png

Java的注解解析類主要是AnnotatedElement接口的實現(xiàn)類,我們可以通過反射獲取一個類的AnnotatedElement對象后,就可以通過下面表格的幾個方法,訪問Annotation信息。

方法返回值 方法 方式解釋
T getAnnotation(Class<T> annotationClass) 返回元素上存在的,指定類型的注解。如果該類型注解不存在,則返回null。
Annotation[] getAnnotations() 返回該元素上的所有注解。
T getDeclaredAnnotation(Class<T> annotationClass) 返回元素上存在,指定類型的注解,忽略繼承注解,如果該類型注解不存在,則返回null。
Annotation[] getDeclaredAnnotations() 返回直接存在于類上的所有注解,忽略繼承注解,如果該元素上沒有任何注解,那么將返回一個長度為0的數(shù)組。
boolean isAnnotationPresent(Class<? extends Annotation>) 判斷程序元素上是否包含指定類型的注解,存在則返回true,否則返回false。

1. 自定義注解:定義

@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodInfo {
    String author() default "xioapang";
    String date();
    int revision() default 1;
    String comments();
}

2. 自定義注解:使用

public class AnnotationExample {
    @MethodInfo(author = "XXX", comments = "toString method", date = "Nov 17 2019", revision = 2)
    public String toString() {
        return "Overriden toString method";
    }
}

3. 自定義注解:解析

@Slf4j
public class AnnotationParsing {
    public static void main(String[] args) {
        try {
            //加載某個類上的所有方法
            for (Method method : AnnotationParsing.class.getClassLoader().loadClass("com.galax.common.anno.customAnno.AnnotationExample").getMethods()) {
                //判斷方法是否存在MethodInfo.class注解
                if (method.isAnnotationPresent(MethodInfo.class)) {
                    //獲取非繼承關(guān)系的所有注解
                    for (Annotation anno : method.getDeclaredAnnotations()) {
                        log.info("注解信息:{} ", anno);
                    }
                    //獲取元素上該注解的詳細信息
                    MethodInfo methodAnnotation = method.getAnnotation(MethodInfo.class);
                    log.info("版本號:{}", methodAnnotation.revision());
                    log.info("作者:{}", methodAnnotation.author());
                    log.info("時間:{}", methodAnnotation.date());
                    log.info("描述:{}", methodAnnotation.comments());
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

文章參考

深入理解Java自定義注解(一):入門

深入理解Java自定義注解(二)-使用自定義注解

Java反射獲取類和對象信息全解析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容