注解的原理-類的常量池

上次講了注解的定義和自定義注解,
但是留了個問題沒有進(jìn)一步說明,就是注解所設(shè)定的數(shù)據(jù)是存在什么地方的曙搬?
這里需要引入一個新東西,類的常量池。

class的結(jié)構(gòu)

對于Java新手來說這部分可能不是很友好纵装,
class文件是java文件編譯后的字節(jié)碼征讲,對于一個class文件來說規(guī)定的結(jié)構(gòu)可以理解為一張表,
下面是class文件結(jié)構(gòu)的規(guī)定搂擦,


image

如果第一次接觸的話可以先忽略具體的各個項目稳诚,
總的說就是Java編譯后的字節(jié)碼按照表的規(guī)定非常嚴(yán)格的以表的結(jié)構(gòu)構(gòu)成。

對于我們要關(guān)注的問題"注解的數(shù)據(jù)存儲在哪里"來說瀑踢,
只需要關(guān)注表里面的 constant_pool 這個部分扳还,
這個稱作常量池的東西,保存了一系列的數(shù)據(jù)橱夭,分為四種

  • Literal氨距,字面量
  • Symbolic References,符號引用
  • Others棘劣,其他
  • constant pool俏让,常量
    注解的數(shù)據(jù)就存在 constant pool這里。

常量池

用比較直觀的方式來理解常量池的話茬暇,最簡單便捷的方式就是看字節(jié)碼首昔,
javap 是一個查看字節(jié)碼的命令,之前多次用過它來理解Java的字節(jié)碼糙俗,
這里我們用 javap來看常量池的話可以執(zhí)行

javap -p Student.Class

輸出

Classfile /Users/zhenghui/StudioProjects/MyProject/AnnotationDemo/Student.class
  Last modified 2018-7-28; size 925 bytes
  MD5 checksum 6ec1e13999388ff134142418179a88d8
  Compiled from "Student.java"
public class Student
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref          #15.#34        // java/lang/Object."<init>":()V
   #2 = Fieldref           #4.#35         // Student.name:Ljava/lang/String;
   #3 = Fieldref           #4.#36         // Student.age:I
   #4 = Class              #37            // Student
   #5 = Methodref          #4.#38         // Student."<init>":(Ljava/lang/String;I)V
   #6 = Fieldref           #39.#40        // java/lang/System.out:Ljava/io/PrintStream;
   #7 = Class              #41            // java/lang/StringBuilder
   #8 = Methodref          #7.#34         // java/lang/StringBuilder."<init>":()V
   #9 = String             #42            // name:
  #10 = Methodref          #7.#43         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #11 = String             #44            //  age:
  #12 = Methodref          #7.#45         // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  #13 = Methodref          #7.#46         // java/lang/StringBuilder.toString:()Ljava/lang/String;
  #14 = Methodref          #47.#48        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #15 = Class              #49            // java/lang/Object
  #16 = Utf8               name
  #17 = Utf8               Ljava/lang/String;
  #18 = Utf8               age
  #19 = Utf8               I
  #20 = Utf8               <init>
  #21 = Utf8               (Ljava/lang/String;I)V
  #22 = Utf8               Code
  #23 = Utf8               LineNumberTable
  #24 = Utf8               createStudent
  #25 = Utf8               (Ljava/lang/String;I)LStudent;
  #26 = Utf8               RuntimeVisibleAnnotations
  #27 = Utf8               LSexual;
  #28 = Utf8               value
  #29 = Utf8               male
  #30 = Utf8               displayInfo
  .... //省略部分內(nèi)容
  {
  java.lang.String name;
    descriptor: Ljava/lang/String;
    flags:

  int age;
    descriptor: I
    flags:
    .... //省略部分內(nèi)容
    public void displayInfo();
      descriptor: ()V
      flags: ACC_PUBLIC
      Code:
        stack=3, locals=1, args_size=1
           0: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
           3: new           #7                  // class java/lang/StringBuilder
           6: dup
           7: invokespecial #8                  // Method java/lang/StringBuilder."<init>":()V
          10: ldc           #9                  // String name:
          12: invokevirtual #10                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          15: aload_0
          16: getfield      #2                  // Field name:Ljava/lang/String;
          19: invokevirtual #10                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          22: ldc           #11                 // String  age:
          24: invokevirtual #10                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          27: aload_0
          28: getfield      #3                  // Field age:I
          31: invokevirtual #12                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
          34: invokevirtual #13                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
          37: invokevirtual #14                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          40: return
        LineNumberTable:
          line 16: 0
          line 17: 40
  }

內(nèi)容比較長勒奇,就只截取其中一部分。
感興趣的話可以自己寫個簡單的類編譯一下巧骚,然后查看完整的字節(jié)碼赊颠,跟上面的大同小異。
上面的字節(jié)碼是從上一個文章中的例子里編譯來的劈彪,
在 Constant pool 這部分保存了我們注解的內(nèi)容竣蹦,關(guān)注
#24 - #29 的內(nèi)容,
這里就是注解所攜帶的信息存放的地方了沧奴。
這里用了一個RuntimeVisibleAnnotations作為標(biāo)注痘括,對應(yīng)注解中的RUNTIME標(biāo)記。
可能跟你一開始理解的不同滔吠,現(xiàn)在應(yīng)該明白远寸,注解的信息并不保存在方法的執(zhí)行棧中,而是在一個叫常量池的地方獨立保存起來屠凶。

關(guān)于class的文件結(jié)構(gòu)可以說很長的篇幅驰后,
比如魔數(shù),比如最大最小版本矗愧,
可能做過gradle插件的同學(xué)會遇到"major.minor version 52.0"這么個問題灶芝,
原因是在低版本的java上使用了高版本的插件導(dǎo)致的郑原,這個 version 52就定義在class文件的 major version 字段。
如果打算進(jìn)階資深Java開發(fā)的話可以仔細(xì)弄清楚這一塊的知識哦夜涕。


公眾號.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末犯犁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子女器,更是在濱河造成了極大的恐慌酸役,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驾胆,死亡現(xiàn)場離奇詭異涣澡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)丧诺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門入桂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人驳阎,你說我怎么就攤上這事抗愁。” “怎么了呵晚?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵蜘腌,是天一觀的道長。 經(jīng)常有香客問我饵隙,道長撮珠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任癞季,我火速辦了婚禮劫瞳,結(jié)果婚禮上倘潜,老公的妹妹穿的比我還像新娘绷柒。我一直安慰自己,他們只是感情好涮因,可當(dāng)我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布废睦。 她就那樣靜靜地躺著,像睡著了一般养泡。 火紅的嫁衣襯著肌膚如雪嗜湃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天澜掩,我揣著相機(jī)與錄音购披,去河邊找鬼。 笑死肩榕,一個胖子當(dāng)著我的面吹牛刚陡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼筐乳,長吁一口氣:“原來是場噩夢啊……” “哼歌殃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蝙云,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤氓皱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后勃刨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體波材,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年朵你,在試婚紗的時候發(fā)現(xiàn)自己被綠了各聘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡抡医,死狀恐怖躲因,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情忌傻,我是刑警寧澤大脉,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站水孩,受9級特大地震影響镰矿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜俘种,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一秤标、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宙刘,春花似錦苍姜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至布近,卻和暖如春垫释,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背撑瞧。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工棵譬, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人预伺。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓订咸,卻偏偏與公主長得像琅束,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子算谈,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,689評論 2 354