最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java中注解的實現(xiàn)原理詳解

 更新時間:2023年10月02日 09:36:55   作者:Archie_java  
這篇文章主要介紹了java中注解的實現(xiàn)原理詳解,注解也叫元數(shù)據(jù),例如我們常見的@Override和@Deprecated,注解是JDK1.5版本開始引入的一個特性,用于對代碼進行說明,可以對包、類、接口、字段、方法參數(shù)、局部變量等進行注解,需要的朋友可以參考下

1.什么是注解

注解也叫元數(shù)據(jù),例如我們常見的@Override和@Deprecated,注解是JDK1.5版本開始引入的一個特性,用于對代碼進行說明,可以對包、類、接口、字段、方法參數(shù)、局部變量等進行注解

一般常用的注解可以分為三類:

  • 一類是Java自帶的標(biāo)準(zhǔn)注解,包括@Override(標(biāo)明重寫某個方法)、@Deprecated(標(biāo)明某個類或方法過時)和@SuppressWarnings(標(biāo)明要忽略的警告),使用這些注解后編譯器就會進行檢查。
  • 一類為元注解,元注解是用于定義注解的注解,包括@Retention(標(biāo)明注解被保留的階段)、@Target(標(biāo)明注解使用的范圍)、@Inherited(標(biāo)明注解可繼承)、@Documented(標(biāo)明是否生成javadoc文檔)
  • 一類為自定義注解,可以根據(jù)自己的需求定義注解

2.注解的用途

在看注解的用途之前,有必要簡單的介紹下XML和注解區(qū)別,

注解:是一種分散式的元數(shù)據(jù),與源代碼緊綁定。

xml:是一種集中式的元數(shù)據(jù),與源代碼無綁定

當(dāng)然網(wǎng)上存在各種XML與注解的辯論哪個更好,這里不作評論和介紹,主要介紹一下注解的主要用途:

  • 生成文檔,通過代碼里標(biāo)識的元數(shù)據(jù)生成javadoc文檔。
  • 編譯檢查,通過代碼里標(biāo)識的元數(shù)據(jù)讓編譯器在編譯期間進行檢查驗證。
  • 編譯時動態(tài)處理,編譯時通過代碼里標(biāo)識的元數(shù)據(jù)動態(tài)處理,例如動態(tài)生成代碼。
  • 運行時動態(tài)處理,運行時通過代碼里標(biāo)識的元數(shù)據(jù)動態(tài)處理,例如使用反射注入實例

3.注解使用演示

這邊總共定義了4個注解來演示注解的使用

  • 定義一個可以注解在Class,interface,enum上的注解,
  • 定義一個可以注解在METHOD上的注解
  • 定義一個可以注解在FIELD上的注解
  • 定義一個可以注解在PARAMETER上的注解

具體代碼如下:

/**
 * 定義一個可以注解在Class,interface,enum上的注解
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnTargetType {
    /**
     * 定義注解的一個元素 并給定默認值
     * @return
     */
    String value() default "我是定義在類接口枚舉類上的注解元素value的默認值";
}
/**
 * 定義一個可以注解在METHOD上的注解
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnTargetMethod {
    /**
     * 定義注解的一個元素 并給定默認值
     */
    String value() default "我是定義在方法上的注解元素value的默認值";
}
/**
 * 定義一個可以注解在FIELD上的注解
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnTargetField {
    /**
     * 定義注解的一個元素 并給定默認值
     */
    String value() default "我是定義在字段上的注解元素value的默認值";
}
/**
 * 定義一個可以注解在PARAMETER上的注解
 */
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnTargetParameter {
    /**
     * 定義注解的一個元素 并給定默認值
     */
    String value() default "我是定義在參數(shù)上的注解元素value的默認值";
}

編寫一個測試處理類處理以上注解,這邊不過多解釋,代碼中都寫了對應(yīng)的注釋如下:

/**
 * 測試java注解類
 */
@MyAnTargetType
public class AnnotationTest {
    @MyAnTargetField
    private String field = "我是字段";
    @MyAnTargetMethod("測試方法")
    public void test(@MyAnTargetParameter String args) {
        System.out.println("參數(shù)值 === "+args);
    }
    public static void main(String[] args) {
        // 獲取類上的注解MyAnTargetType
        MyAnTargetType t = AnnotationTest.class.getAnnotation(MyAnTargetType.class);
        System.out.println("類上的注解值 === "+t.value());
        MyAnTargetMethod tm = null;
        try {
            // 根據(jù)反射獲取AnnotationTest類上的test方法
            Method method = AnnotationTest.class.getDeclaredMethod("test",String.class);
            // 獲取方法上的注解MyAnTargetMethod
            tm = method.getAnnotation(MyAnTargetMethod.class);
            System.out.println("方法上的注解值 === "+tm.value());
            // 獲取方法上的所有參數(shù)注解  循環(huán)所有注解找到MyAnTargetParameter注解
            Annotation[][] annotations = method.getParameterAnnotations();
            for(Annotation[] tt : annotations){
                for(Annotation t1:tt){
                    if(t1 instanceof MyAnTargetParameter){
                        System.out.println("參數(shù)上的注解值 === "+((MyAnTargetParameter) t1).value());
                    }
                }
            }
            method.invoke(new AnnotationTest(), "改變默認參數(shù)");
            // 獲取AnnotationTest類上字段field的注解MyAnTargetField
            MyAnTargetField fieldAn = AnnotationTest.class.getDeclaredField("field").getAnnotation(MyAnTargetField.class);
            System.out.println("字段上的注解值 === "+fieldAn.value());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

運行結(jié)果如下:

類上的注解值 === 我是定義在類接口枚舉類上的注解元素value的默認值
參數(shù)上的注解值 === 我是定義在參數(shù)上的注解元素value的默認值
參數(shù)值 === 改變默認參數(shù)
方法上的注解值 === 測試方法
字段上的注解值 === 我是定義在字段上的注解元素value的默認值

4.注解的實現(xiàn)原理

以上只抽取了注解的其中幾種類型演示,下面讓我們一起來看看他們是怎么工作的

讓我們先看一下實現(xiàn)注解三要素:

1,注解聲明、

2,使用注解的元素、

3,操作注解使其起作用(注解處理器)

注解聲明

首先我們讓看一下java中的元注解(也就是上面提到的注解的注解),總共有4個如下:

  • @Target,
  • @Retention,
  • @Documented,
  • @Inherited

這4個元注解都是在jdk的java.lang.annotation包下面

@Target

Target說明的是Annotation所修飾的對象范圍,源碼如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

其中只有一個元素ElementType,再看看它的源碼如下:

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,
    /** Field declaration (includes enum constants) */
    FIELD,
    /** Method declaration */
    METHOD,
    /** Formal parameter declaration */
    PARAMETER,
    /** Constructor declaration */
    CONSTRUCTOR,
    /** Local variable declaration */
    LOCAL_VARIABLE,
    /** Annotation type declaration */
    ANNOTATION_TYPE,
    /** Package declaration */
    PACKAGE,
    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,
    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

ElementType是一個枚舉類定義注解可以作用的類型上,上面例子中演示了TYPE,F(xiàn)IELD,METHOD,PARAMETER 4種可以作用的目標(biāo)

@Retention

定義了該Annotation被保留的時間長短:某些Annotation僅出現(xiàn)在源代碼中,而被編譯器丟棄;而另一些卻被編譯在class文件中;編譯在class文件中的Annotation可能會被虛擬機忽略,而另一些在class被裝載時將被讀?。ㄕ堊⒁獠⒉挥绊慶lass的執(zhí)行,因為Annotation與class在使用上是被分離的)。使用這個元注解可以對 Annotation的“生命周期”限制

@Documented

@Documented用于描述其它類型的annotation應(yīng)該被作為被標(biāo)注的程序成員的公共API,因此可以被例如javadoc此類的工具文檔化。Documented是一個標(biāo)記注解,沒有成員

@Inherited

@Inherited 元注解是一個標(biāo)記注解,@Inherited闡述了某個被標(biāo)注的類型是被繼承的。如果一個使用了@Inherited修飾的annotation類型被用于一個class,則這個annotation將被用于該class的子類

注意:@Inherited annotation類型是被標(biāo)注過的class的子類所繼承。類并不從它所實現(xiàn)的接口繼承annotation,方法并不從它所重載的方法繼承annotation。

當(dāng)@Inherited annotation類型標(biāo)注的annotation的Retention是RetentionPolicy.RUNTIME,則反射API增強了這種繼承性。如果我們使用java.lang.reflect去查詢一個@Inherited annotation類型的annotation時,反射代碼檢查將展開工作:檢查class和其父類,直到發(fā)現(xiàn)指定的annotation類型被發(fā)現(xiàn),或者到達類繼承結(jié)構(gòu)的頂層。

這邊針對這個小編專門寫了一個例子方便大家理解,在以上MyAnTargetType注解類中增加@Inherited注解,如下:

/**
 * 定義一個可以注解在Class,interface,enum上的注解
 * 增加了@Inherited注解代表允許繼承
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnTargetType {
    /**
     * 定義注解的一個元素 并給定默認值
     * @return
     */
    String value() default "我是定義在類接口枚舉類上的注解元素value的默認值";
}

增加一個子類ChildAnnotationTest繼承AnnotationTest測試如下:

/**
 * 增加一個子類繼承AnnotationTest 演示@Inherited注解允許繼承
 */
public class ChildAnnotationTest extends AnnotationTest {
    public static void main(String[] args) {
        // 獲取類上的注解MyAnTargetType
        MyAnTargetType t = ChildAnnotationTest.class.getAnnotation(MyAnTargetType.class);
        System.out.println("類上的注解值 === "+t.value());
    }
}

運行如下:

類上的注解值 === 我是定義在類接口枚舉類上的注解元素value的默認值

說明已經(jīng)獲取到了父類AnnotationTest的注解了

如果MyAnTargetType去掉@Inherited注解運行則報錯如下:

Exception in thread "main" java.lang.NullPointerException
    at com.zhang.run.ChildAnnotationTest.main(ChildAnnotationTest.java:17)

使用注解的元素

使用注解沒什么好說的就是在你需要的地方加上對應(yīng)的你寫好的注解就行

注解處理器

這個是注解使用的核心了,前面我們說了那么多注解相關(guān)的,那到底java是如何去處理這些注解的呢

從getAnnotation進去可以看到j(luò)ava.lang.class實現(xiàn)了AnnotatedElement方法

MyAnTargetType t = AnnotationTest.class.getAnnotation(MyAnTargetType.class);
public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement

java.lang.reflect.AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通過反射獲取了某個類的AnnotatedElement對象之后,程序就可以調(diào)用該對象的如下四個個方法來訪問Annotation信息:

  • 方法1: T getAnnotation(Class annotationClass): 返回改程序元素上存在的、指定類型的注解,如果該類型注解不存在,則返回null。
  • 方法2:Annotation[] getAnnotations():返回該程序元素上存在的所有注解。
  • 方法3:boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判斷該程序元素上是否包含指定類型的注解,存在則返回true,否則返回false.
  • 方法4:Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注釋。與此接口中的其他方法不同,該方法將忽略繼承的注釋。(如果沒有注釋直接存在于此元素上,則返回長度為零的一個數(shù)組。)該方法的調(diào)用者可以隨意修改返回的數(shù)組;這不會對其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響

到此這篇關(guān)于java中注解的實現(xiàn)原理詳解的文章就介紹到這了,更多相關(guān)java注解的原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java反射概念與使用實例代碼

    Java反射概念與使用實例代碼

    JAVA反射機制是在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法,下面這篇文章主要給大家介紹了關(guān)于Java反射概念與使用的相關(guān)資料,需要的朋友可以參考下
    2021-11-11
  • 基于Java語言的遞歸運算例題詳解

    基于Java語言的遞歸運算例題詳解

    一個方法在執(zhí)行過程中調(diào)用自身, 就稱為 "遞歸"。本文將通過幾個例題帶大家深入了解一下Java語言中的遞歸運算,感興趣的可以了解一下
    2022-08-08
  • mybatis-plus多表查詢操作方法

    mybatis-plus多表查詢操作方法

    這篇文章主要介紹了mybatis-plus多表查詢操作方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2023-12-12
  • Spring?Native打包本地鏡像的操作方法(無需通過Graal的maven插件buildtools)

    Spring?Native打包本地鏡像的操作方法(無需通過Graal的maven插件buildtools)

    這篇文章主要介紹了Spring?Native打包本地鏡像,無需通過Graal的maven插件buildtools,本文探索一下,如果不通過這個插件來生成鏡像,結(jié)合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2023-02-02
  • spring security環(huán)境搭建

    spring security環(huán)境搭建

    本文通過代碼給大家介紹了spring security環(huán)境搭建的詳細教程,非常不錯,具有參考借鑒價值,需要的朋友參考下吧
    2017-09-09
  • Java圓通物流軌跡推送服務(wù)接口文檔及流程

    Java圓通物流軌跡推送服務(wù)接口文檔及流程

    這篇文章主要介紹了圓通物流軌跡推送服務(wù)接口Java文檔,主要用來接收圓通推送的訂單狀態(tài),本文給大家分享詳細流程,感興趣的朋友跟隨小編一起看看吧
    2022-02-02
  • 如何自定義springboot-starter日志組件供各個服務(wù)使用(系統(tǒng)日志優(yōu)化)

    如何自定義springboot-starter日志組件供各個服務(wù)使用(系統(tǒng)日志優(yōu)化)

    文章介紹了如何將各個微服務(wù)的接口調(diào)用日志邏輯優(yōu)化為一個可共享的Spring Boot Starter,通過自定義注解和自動裝配機制實現(xiàn),本文給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2025-01-01
  • Java設(shè)計模式之開閉原則精解

    Java設(shè)計模式之開閉原則精解

    設(shè)計模式(Design?pattern)代表了最佳的實踐,通常被有經(jīng)驗的面向?qū)ο蟮能浖_發(fā)人員所采用。設(shè)計模式是軟件開發(fā)人員在軟件開發(fā)過程中面臨的一般問題的解決方案。本篇介紹設(shè)計模式七大原則之一的開閉原則
    2022-02-02
  • Java開發(fā)者必備10大數(shù)據(jù)工具和框架

    Java開發(fā)者必備10大數(shù)據(jù)工具和框架

    這篇文章主要為大家詳細介紹了Java開發(fā)者必備10大數(shù)據(jù)工具和框架,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • SpringBoot實現(xiàn)Read Through模式的操作過程

    SpringBoot實現(xiàn)Read Through模式的操作過程

    Read Through模式通常是指一種緩存策略,其中當(dāng)應(yīng)用程序嘗試讀取數(shù)據(jù)時,緩存系統(tǒng)首先被檢查以查看數(shù)據(jù)是否已經(jīng)存在于緩存中,這篇文章主要介紹了SpringBoot實現(xiàn)Read Through模式,需要的朋友可以參考下
    2024-07-07

最新評論

岢岚县| 怀远县| 垦利县| 镶黄旗| 桂林市| 饶河县| 惠水县| 武汉市| 淳化县| 耿马| 富顺县| 隆尧县| 定远县| 临澧县| 宜宾市| 洛南县| 水城县| 双柏县| 屯门区| 永德县| 那曲县| 六盘水市| 庄浪县| 武冈市| 登封市| 盐源县| 中方县| 湖北省| 呼玛县| 通道| 应用必备| 大名县| 毕节市| 德兴市| 焉耆| 霍邱县| 阜新市| 宁德市| 甘南县| 千阳县| 朝阳县|