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

Java 注解的底層原理解析(java基礎(chǔ)面試必問)

 更新時(shí)間:2026年04月08日 09:01:28   作者:Lyyaoo.  
本文介紹了Java注解的基本概念及其生命周期、使用位置等元注解的定義和使用方法,詳細(xì)解釋了注解的在編譯、類加載和運(yùn)行時(shí)的處理過程,并通過實(shí)例說明了注解在反射API中的實(shí)現(xiàn)原理,感興趣的朋友跟隨小編一起看看吧

前言

注解是 Java 5 引入的一種元數(shù)據(jù)機(jī)制,可以在代碼中添加信息,這些信息可以被編譯器、開發(fā)工具或運(yùn)行時(shí)環(huán)境使用。

注解的本質(zhì)是一個(gè)繼承了Annotation的接口

 Java 注解(Annotation)是一種元數(shù)據(jù),它本身不直接影響代碼邏輯,但可以被編譯器、工具或框架在編譯時(shí)或運(yùn)行時(shí)讀取并處理。

 注解實(shí)際上是一個(gè)接口,它隱式地繼承自 java.lang.annotation.Annotation 接口。注解中定義的方法對(duì)應(yīng)注解的“屬性”。這些方法沒有參數(shù),返回值類型受限(基本類型、String、Class、枚舉、注解以及它們的數(shù)組)。

 對(duì)于一個(gè)簡(jiǎn)單的自定義注解,使用 @interface 關(guān)鍵字進(jìn)行實(shí)現(xiàn)

public @interface MyAnnotation {
    String value() default "";
}

 用 javap -c MyAnnotation 反編譯后,會(huì)看到,

public interface MyAnnotation extends java.lang.annotation.Annotation {
  public abstract java.lang.String value();
}

元注解

 Java 提供了幾個(gè)元注解(即注解的注解),用來定義注解的生命周期、使用位置等。

元注解作用
@Target指定注解可以用在哪些地方(類、方法、字段、參數(shù)等)。
@Retention指定注解保留到哪個(gè)階段(源碼、字節(jié)碼、運(yùn)行時(shí))。
@Documented是否包含在 Javadoc 中。
@Inherited是否允許子類繼承父類的注解。
@Repeatable(Java 8)允許同一位置重復(fù)使用同一個(gè)注解。

@Target注解

 @Target 接收一個(gè) ElementType 數(shù)組,表示該注解可以出現(xiàn)在哪些地方。常用的 ElementType 枚舉值包括:

ElementType說明
TYPE類、接口、枚舉、注解類型
FIELD成員變量(包括枚舉常量)
METHOD方法
PARAMETER方法參數(shù)
CONSTRUCTOR構(gòu)造方法
LOCAL_VARIABLE局部變量
ANNOTATION_TYPE注解類型(用于元注解)
PACKAGE
TYPE_PARAMETER(Java 8)類型參數(shù)(如 class MyClass 中的 T)
TYPE_USE(Java 8)類型使用處(如 new @NonNull String())

@Retention注解

  • SOURCE:注解只保留在源代碼中,編譯時(shí)被丟棄(如 @Override、@SuppressWarnings)。這類注解僅用于編譯期檢查,不會(huì)進(jìn)入 .class 文件。
  • CLASS(默認(rèn)):注解保留在 .class 文件中,但加載到 JVM 時(shí)會(huì)被忽略(即運(yùn)行時(shí)無法通過反射獲?。?。這種級(jí)別通常用于字節(jié)碼操作工具(如 Lombok)。
  • RUNTIME:注解保留在 .class 文件中,并且在運(yùn)行時(shí)可以被 JVM 讀?。ㄍㄟ^反射)。這是框架最常用的級(jí)別(如 @Autowired、@RequestMapping)。

注解在字節(jié)碼中的存儲(chǔ)

編譯階段

 當(dāng)編譯器處理帶有注解的代碼時(shí),會(huì)根據(jù) @Retention 決定是否將注解信息寫入 .class 文件。對(duì)于 RUNTIME 或 CLASS 級(jí)別的注解,編譯器會(huì)在字節(jié)碼中添加專門的屬性表(Attribute)。

 以 @MyAnnotation 標(biāo)注一個(gè)類為例:

@MyAnnotation("hello")
public class Test {}

 用 javap -v Test 查看字節(jié)碼,會(huì)看到類似:

RuntimeVisibleAnnotations:
  0: #10(#11=s#12)
    #10 = Utf8 "LMyAnnotation;"
    #11 = Utf8 "value"
    #12 = Utf8 "hello"

 RuntimeVisibleAnnotations 是字節(jié)碼中的一種屬性,表示在運(yùn)行時(shí)可見的注解列表。每個(gè)注解被編碼為:注解類型 + 屬性名 + 屬性值。例子中的類型為 LMyAnnotation;,屬性名是value,屬性值是hello。

類加載階段

 JVM 在加載類時(shí),會(huì)讀取 .class 文件中的這些屬性,將注解信息解析并存儲(chǔ)到類的元數(shù)據(jù)中(方法區(qū)的 Annotation 數(shù)據(jù)結(jié)構(gòu))。但對(duì)于 @Retention(CLASS) 的注解,在類加載后這些信息會(huì)被丟棄;而對(duì)于 RUNTIME 的注解,會(huì)保留在運(yùn)行時(shí)。

運(yùn)行時(shí)注解(反射API)

JVM自動(dòng)生成動(dòng)態(tài)代理對(duì)象來實(shí)現(xiàn)注解接口,可通過代理對(duì)象的 invoke 方法實(shí)現(xiàn)對(duì)注解中屬性對(duì)應(yīng)值的返回(自定義注解中的 value 的對(duì)應(yīng)屬性值)

 當(dāng)注解的 @Retention 為 RUNTIME 時(shí),才可以通過反射 API 獲取注解信息

Annotation[] annotations = Test.class.getAnnotations();
MyAnnotation myAnno = Test.class.getAnnotation(MyAnnotation.class);
String value = myAnno.value();
  • Class.getAnnotation(Class) 最終會(huì)調(diào)用 JVM 內(nèi)部的 native 方法,遍歷類的 RuntimeVisibleAnnotations 表。
  • 對(duì)于找到的每個(gè)注解,JVM 會(huì)動(dòng)態(tài)生成一個(gè)代理對(duì)象(java.lang.reflect.Proxy)來實(shí)現(xiàn)該注解接口。
  • 這個(gè)代理對(duì)象內(nèi)部有一個(gè) AnnotationInvocationHandler(在 sun.reflect.annotation 包下),它維護(hù)了一個(gè) Map<String, Object>,里面存放了解析出的注解屬性名和值(例如 {“value”: “hello”})
  • 代理對(duì)象的 invoke 方法會(huì)根據(jù)注解屬性名返回對(duì)應(yīng)的值(這些值存儲(chǔ)在字節(jié)碼中,由 JVM 解析后保存)。
  • 因此,myAnno.value() 實(shí)際執(zhí)行的是代理對(duì)象的方法調(diào)用,而不是某個(gè)實(shí)現(xiàn)類的實(shí)例方法。

@MyAnnotation(“hello”) 本質(zhì)上是 @MyAnnotation(value = “hello”),相當(dāng)于給value賦值為 “hello”,調(diào)用myAnno.value()本質(zhì)上調(diào)用代理對(duì)象的 invoke 方法,最終返回屬性值。

到此這篇關(guān)于【Java基礎(chǔ)面經(jīng)】Java 注解的底層原理的文章就介紹到這了,更多相關(guān)Java 注解原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot中@RequestBody不能和Multipart同時(shí)傳遞的問題解決

    SpringBoot中@RequestBody不能和Multipart同時(shí)傳遞的問題解決

    本文主要介紹了SpringBoot中@RequestBody不能和Multipart同時(shí)傳遞的問題解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Mybatis批量插入index out of range錯(cuò)誤的解決(較偏的錯(cuò)誤)

    Mybatis批量插入index out of range錯(cuò)誤的解決(較偏的錯(cuò)誤)

    這篇文章主要介紹了Mybatis批量插入index out of range錯(cuò)誤的解決(較偏的錯(cuò)誤),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • mybatisplus按條件修改實(shí)體單個(gè)字段實(shí)現(xiàn)方式

    mybatisplus按條件修改實(shí)體單個(gè)字段實(shí)現(xiàn)方式

    在MyBatis-Plus中,可以使用UpdateWrapper/LambdaUpdateWrapper按條件修改實(shí)體單個(gè)字段,推薦使用LambdaUpdateWrapper,它具有類型安全、清晰、高效等優(yōu)點(diǎn),避免使用updateById()或傳入實(shí)體對(duì)象的方式,通過示例展示如何正確使用UpdateWrapper進(jìn)行單個(gè)字段的更新
    2026-04-04
  • Mybatis多參數(shù)及實(shí)體對(duì)象傳遞實(shí)例講解

    Mybatis多參數(shù)及實(shí)體對(duì)象傳遞實(shí)例講解

    在使用Mybatis的時(shí)候,經(jīng)常會(huì)有各種各樣的參數(shù)傳遞,不同類型,不同個(gè)數(shù)的參數(shù),下面小編通過例子給大家講解下Mybatis多參數(shù)及實(shí)體對(duì)象傳遞,一起看看吧
    2016-12-12
  • java.lang.Long cannot be cast to java.lang.Integer數(shù)據(jù)類型轉(zhuǎn)換異常解決辦法

    java.lang.Long cannot be cast to ja

    本文主要介紹了java.lang.Long cannot be cast to java.lang.Integer數(shù)據(jù)類型轉(zhuǎn)換異常解決辦法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • JVM?中的?returnAddress過程詳解

    JVM?中的?returnAddress過程詳解

    JVM的畢竟是個(gè)虛擬機(jī),是一種規(guī)范,雖說符合馮諾依曼的計(jì)算機(jī)設(shè)計(jì)理念,但是他并不是實(shí)體計(jì)算機(jī),所以他的組成也不是什么存儲(chǔ)器,控制器,運(yùn)算 器,輸入輸出設(shè)備,本文給大家介紹JVM?中的?returnAddress,感興趣的朋友一起看看吧
    2022-04-04
  • SpringBoot 多線程事務(wù)回滾的實(shí)現(xiàn)

    SpringBoot 多線程事務(wù)回滾的實(shí)現(xiàn)

    本文是基于springboot的@Async注解開啟多線程,并通過自定義注解和AOP實(shí)現(xiàn)的多線程事務(wù),避免繁瑣的手動(dòng)提交/回滾事務(wù),感興趣的可以了解一下
    2024-02-02
  • 學(xué)習(xí)Java之Java中的異常處理機(jī)制詳解

    學(xué)習(xí)Java之Java中的異常處理機(jī)制詳解

    在本文中,小編將帶領(lǐng)大家來學(xué)習(xí)Java的異常處理機(jī)制,包括異常機(jī)制、異常類型、如何捕獲異常、如何拋出異常以及如何創(chuàng)建自定義異常等核心內(nèi)容,感興趣的同學(xué)跟著小編一起來看看吧
    2023-08-08
  • Java使用POI實(shí)現(xiàn)導(dǎo)出Excel的方法詳解

    Java使用POI實(shí)現(xiàn)導(dǎo)出Excel的方法詳解

    在項(xiàng)目開發(fā)中往往需要使用到Excel的導(dǎo)入和導(dǎo)出,導(dǎo)入就是從Excel中導(dǎo)入到DB中,而導(dǎo)出就是從DB中查詢數(shù)據(jù)然后使用POI寫到Excel上。本文將利用POI實(shí)現(xiàn)導(dǎo)出Excel,需要的可以參考一下
    2022-10-10
  • SpringBoot啟動(dòng)執(zhí)行sql腳本的3種方法實(shí)例

    SpringBoot啟動(dòng)執(zhí)行sql腳本的3種方法實(shí)例

    在應(yīng)用程序啟動(dòng)后,可以自動(dòng)執(zhí)行建庫、建表等SQL腳本,下面這篇文章主要給大家介紹了關(guān)于SpringBoot啟動(dòng)執(zhí)行sql腳本的3種方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-01-01

最新評(píng)論

雅江县| 中山市| 香格里拉县| 巴南区| 类乌齐县| 确山县| 恭城| 任丘市| 江山市| 河源市| 大英县| 岑巩县| 腾冲县| 大方县| 贵阳市| 西平县| 阳城县| 耿马| 民和| 云浮市| 伊金霍洛旗| 武汉市| 永州市| 涞水县| 璧山县| 专栏| 娄底市| 沧源| 卫辉市| 本溪市| 吉首市| 桃园县| 黄梅县| 乌苏市| 文安县| 沐川县| 晋州市| 安乡县| 扎兰屯市| 洛川县| 宝应县|