0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

JAVA中注解是怎么做到的(下)

jf_78858299 ? 來源:JAVA旭陽 ? 作者:JAVA旭陽 ? 2023-05-11 10:57 ? 次閱讀

使用反射操作注解

大部分情況下,我們的項目或者開源框架中都定義了大量的注解,而且都是@Retention(RetentionPolicy.RUNTIME)運行時階段,我們可以通過反射獲取注解中的信息,所以整體遵循下面的一個范式。

  1. 自定義注解
  2. 掃描注解
  3. 通過反射獲取注解的信息,執(zhí)行相應(yīng)的邏輯。

下面我們重點使用下如何用反射來獲取注解的信息。

  1. 定義target是注解的注解
@Inherited
@Retention( value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.ANNOTATION_TYPE})
public @interface AnnoTest {

    String value() default "anno";

}
  1. 定義一個幾乎全量信息的注解
@AnnoTest("alvinAnno")
@Inherited
@Retention( value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE_USE,ElementType.PACKAGE,ElementType.FIELD,
        ElementType.TYPE_PARAMETER,ElementType.CONSTRUCTOR,ElementType.LOCAL_VARIABLE})
@Documented
public @interface FullAnnoTest {

    String value() default  "FullAnnoTest";

}
  1. 定義測試類和反射代碼
@FullAnnoTest("package")
package com.alvin.java.core.anno;

public class ParentObj {
}



@FullAnnoTest("testAnnoReflect")
public class TestAnnoReflect<@FullAnnoTest("parameter") T > extends @FullAnnoTest("parent")ParentObj {

    @FullAnnoTest("constructor")
    TestAnnoReflect() {
    }

    //注解字段域
    private @FullAnnoTest("name") String name;
    //注解泛型字段域
    private @FullAnnoTest("value") T value;
    //注解通配符
    private @FullAnnoTest("list") List<@FullAnnoTest("generic") ?> list;
    //注解方法
    @FullAnnoTest("method")                       //注解方法參數(shù)
    public String hello(@FullAnnoTest("methodParameter") String name)
            throws @FullAnnoTest("Exception") Exception { // 注解拋出異常
        //注解局部變量,現(xiàn)在運行時暫時無法獲?。ê雎裕?/span>
        @FullAnnoTest("result") String result;
        result = "siting";
        System.out.println(name);
        return  result;
    }

    public static void main(String[] args) throws Exception {

        TestAnnoReflect
  1. 查看對應(yīng)的執(zhí)行結(jié)果
修飾TestAnnoReflect.class注解value: testAnnoReflect
修飾構(gòu)造器的注解value: constructor
修飾繼承父類的注解value: parent
修飾注解的注解AnnoTest-value: alvinAnno
修飾泛型參數(shù)T注解value: parameter
修飾普通字段域name注解value: name
修飾泛型字段T注解value: value
修飾泛型注解value: list
修飾通配符注解value: generic
修飾方法的注解value: method
修飾方法拋出錯誤的注解value: Exception
修飾方法參數(shù)注解value: methodParameter
修飾package注解value: package
hello

注解的本質(zhì)和底層實現(xiàn)

大家有沒有想過注解的本質(zhì)是什么?

我們先通過反編譯查看注解生成的字節(jié)碼,可以通過javap -v FullAnnoTest.class查看如下:

圖片

可以看到,我們的注解是繼承自Annotation接口。

public interface Annotation {
    boolean equals(Object obj);

    int hashCode();

    String toString();

    /**
     * Returns the annotation type of this annotation.
     * @return the annotation type of this annotation
     */
    Class? extends Annotation annotationType();
}

所以注解相當(dāng)于一個語法糖一樣,可以方便我們使用,本質(zhì)上它是繼承自Annotation的一個接口。

那大家有沒有想過它的實現(xiàn)類在哪里?比如下面的代碼,獲取到注解,按照上面的解釋,它是一個接口,那調(diào)用value()方法時,它具體調(diào)用的哪個實現(xiàn)類呢?我們并沒有寫實現(xiàn)類啊.....

答案當(dāng)然就是動態(tài)代理生成的實現(xiàn)類。

AnnoTest annoTest = testTmp.annotationType().getAnnotation(AnnoTest.class);
System.out.println("修飾注解的注解AnnoTest-value: "+annoTest.value());

我們可以在啟動參數(shù)添加如下命令可以查看生成的代理類:-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true

圖片

執(zhí)行后,生成代理類如下,

圖片

代理大致的代碼如下:

public final class $Proxy2 extends Proxy implements FullAnnoTest {
    private static Method m1;
    private static Method m2;
    private static Method m4;
    private static Method m0;
    private static Method m3;

    public $Proxy2(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

  

    public final Class annotationType() throws  {
        try {
            return (Class)super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String value() throws  {
        try {
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("com.alvin.java.core.anno.FullAnnoTest").getMethod("annotationType");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m3 = Class.forName("com.alvin.java.core.anno.FullAnnoTest").getMethod("value");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

我們看value()方法,這里調(diào)用了super.h對象,也就是InvocationHandler對象,而我們注解用的是AnnotationInvocationHandler這個子類,我們在invoke方法中打個斷點,就明白了~~

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2946

    瀏覽量

    104362
  • JDK
    JDK
    +關(guān)注

    關(guān)注

    0

    文章

    80

    瀏覽量

    16563
  • spring框架
    +關(guān)注

    關(guān)注

    0

    文章

    7

    瀏覽量

    2039
收藏 人收藏

    評論

    相關(guān)推薦

    Java中注解的作用

    Annotation 注解(Annotation),也叫元數(shù)據(jù)。一種代碼級別的說明。它是JDK1.5及以后版本引入的一個特性,與類、接口、枚舉是在同一個層次。它可以聲明在包、類、字段、方法、局部變量
    的頭像 發(fā)表于 09-30 10:12 ?891次閱讀
    <b class='flag-5'>Java</b><b class='flag-5'>中注解</b>的作用

    如何通過注解來優(yōu)化我們的Java代碼

    Java注解可以說是我們編碼過程中最常用的。本篇文章將給大家介紹Java注解的概念、作用以及如何使用注解來提升代碼的可讀性和靈活性,并介紹如
    的頭像 發(fā)表于 09-30 11:39 ?551次閱讀

    PCB刻制線圈怎么做到

    `如附圖這種PCB刻制線圈是怎么做的,畫得這么圓是怎么做到的?`
    發(fā)表于 06-13 11:07

    詳細(xì)介紹了Java泛型、注解、并發(fā)編程

    介紹了Java泛型、注解、并發(fā)編程、數(shù)據(jù)傳輸與序列化、高效IO、容器集合、反射與類加載以及JVM重點知識線程、內(nèi)存模型、JVM運行時內(nèi)存、垃圾回收與算法、Java中四種引用類型、GC 分代收集算法
    發(fā)表于 08-20 06:09

    HarmonyOS注解的使用方法分享

    定義我們的注解自定義注解1、聲明注解功能:檢測類中是否有規(guī)范的get方法新建java libray的module,命名為annotation,創(chuàng)建
    發(fā)表于 03-28 14:04

    斬波型運放減少噪聲 怎么做到的?

    翻譯: TI信號鏈工程師 Tom Wang (王中南) 斬波型運放提供較低的失調(diào)電壓,同時也極大地減少了1 / f(閃爍)噪聲。它是怎么做到的?這篇短文就來討論這個主題。
    發(fā)表于 04-08 04:04 ?1.1w次閱讀
    斬波型運放減少噪聲 <b class='flag-5'>怎么做到</b>的?

    分析java注解基本概念

    什么是注解(Annotation): Annotation(注解)就是Java提供了一種元程序中的元素關(guān)聯(lián)任何信息和著任何元數(shù)據(jù)(metadata)的途徑和方法。Annotion(注解
    發(fā)表于 09-27 14:53 ?0次下載

    怎么做到快速修補板式喂料機軸頭磨損

    怎么做到快速修補板式喂料機軸頭磨損
    發(fā)表于 01-23 11:10 ?2次下載

    Spring Boot常用注解與使用方式

    企業(yè)開發(fā)項目SpringBoot已經(jīng)是必備框架了,其中注解是開發(fā)中的小工具(誰處可見哦),用好了開發(fā)效率大大提升,當(dāng)然用錯了也會引入缺陷。
    的頭像 發(fā)表于 07-08 10:57 ?1292次閱讀

    注解定義Bean及開發(fā)

    注解本質(zhì)是一個繼承了Annotation 的特殊接口,其具體實現(xiàn)類是Java 運行時生成的動態(tài)代理類。
    發(fā)表于 08-02 10:26 ?416次閱讀

    JAVA中注解怎么做到的(上)

    。它可以聲明在包、類、字段、方法、局部變量、方法參數(shù)等的前面,用來對這些元素進(jìn)行說明,注釋。那么你知道JDK什么是元注解嗎?注解有哪些分類嗎?以及注解Java中最本質(zhì)究竟是什么東西,
    的頭像 發(fā)表于 05-11 10:57 ?602次閱讀

    3分鐘純Java注解搭個管理系統(tǒng)

    Erupt一個通用后臺管理框架,據(jù)說有 超低代碼量 、 零前端代碼 、零 CURD操作 、無需建表 ,純Java注解開發(fā) 等特色,號稱三分鐘就可以搭建一個完整的后臺管理系統(tǒng)。
    的頭像 發(fā)表于 07-28 11:27 ?982次閱讀
    3分鐘純<b class='flag-5'>Java</b><b class='flag-5'>注解</b>搭個管理系統(tǒng)

    怎么做到EMC設(shè)計與產(chǎn)品設(shè)計同步?(上)

    怎么做到EMC設(shè)計與產(chǎn)品設(shè)計同步?|深圳比創(chuàng)達(dá)EMC(上)
    的頭像 發(fā)表于 08-28 14:56 ?455次閱讀
    <b class='flag-5'>怎么做到</b>EMC設(shè)計與產(chǎn)品設(shè)計同步?(上)

    怎么做到EMC設(shè)計與產(chǎn)品設(shè)計同步?(中)

    怎么做到EMC設(shè)計與產(chǎn)品設(shè)計同步?(中)相信不少人是有疑問的,今天深圳市比創(chuàng)達(dá)電子科技有限公司就跟大家解答一!
    的頭像 發(fā)表于 08-29 10:34 ?402次閱讀

    怎么做到EMC設(shè)計與產(chǎn)品設(shè)計同步?(

    怎么做到EMC設(shè)計與產(chǎn)品設(shè)計同步?|深圳比創(chuàng)達(dá)EMC(
    的頭像 發(fā)表于 08-30 10:44 ?401次閱讀