亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java class文件格式之常量池_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

 更新時(shí)間:2021年09月09日 09:17:56   作者:zhangjg  
這篇文章主要為大家詳細(xì)介紹了Java class文件格式之常量池的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

常量池中各數(shù)據(jù)項(xiàng)類(lèi)型詳解

常量池中的數(shù)據(jù)項(xiàng)是通過(guò)索引來(lái)引用的, 常量池中的各個(gè)數(shù)據(jù)項(xiàng)之間也會(huì)相互引用。在這11中常量池?cái)?shù)據(jù)項(xiàng)類(lèi)型中, 有兩種比較基礎(chǔ), 之所以說(shuō)它們基礎(chǔ), 是因?yàn)檫@兩種類(lèi)型的數(shù)據(jù)項(xiàng)會(huì)被其他類(lèi)型的數(shù)據(jù)項(xiàng)引用。 這兩種數(shù)據(jù)類(lèi)型就是CONSTANT_Utf8 和 CONSTANT_NameAndType , 其中CONSTANT_NameAndType類(lèi)型的數(shù)據(jù)項(xiàng)(CONSTANT_NameAndType_info)也會(huì)引用CONSTANT_Utf8類(lèi)型的數(shù)據(jù)項(xiàng)(CONSTANT_Utf8_info) 。 與其他介紹常量池的書(shū)籍或其他資料不同, 本著循序漸進(jìn)和先后分明的原則, 我們首先對(duì)這兩種比較基本的類(lèi)型的數(shù)據(jù)項(xiàng)進(jìn)行介紹, 然后再依次介紹其他9中數(shù)據(jù)項(xiàng)。

(1) CONSTANT_Utf8_info

一個(gè)CONSTANT_Utf8_info是一個(gè)CONSTANT_Utf8類(lèi)型的常量池?cái)?shù)據(jù)項(xiàng), 它存儲(chǔ)的是一個(gè)常量字符串。 常量池中的所有字面量幾乎都是通過(guò)CONSTANT_Utf8_info描述的。下面我們首先講解CONSTANT_Utf8_info數(shù)據(jù)項(xiàng)的存儲(chǔ)格式。在前面的文章中, 我們提到, 常量池中數(shù)據(jù)項(xiàng)的類(lèi)型由一個(gè)整型的標(biāo)志值(tag)決定, 所以所有常量池類(lèi)型的info中都必須有一個(gè)tag信息, 并且這個(gè)tag值位于數(shù)據(jù)項(xiàng)的第一個(gè)字節(jié)上。 一個(gè)11中常量池?cái)?shù)據(jù)類(lèi)型, 所以就有11個(gè)tag值表示這11中類(lèi)型。而CONSTANT_Utf8_info的tag值為1, 也就是說(shuō)如果虛擬機(jī)要解析一個(gè)常量池?cái)?shù)據(jù)項(xiàng), 首先去讀這個(gè)數(shù)據(jù)項(xiàng)的第一個(gè)字節(jié)的tag值, 如果這個(gè)tag值為1, 那么就說(shuō)明這個(gè)數(shù)據(jù)項(xiàng)是一個(gè)CONSTANT_Utf8類(lèi)型的數(shù)據(jù)項(xiàng)。 緊挨著tag值的兩個(gè)字節(jié)是存儲(chǔ)的字符串的長(zhǎng)度length, 剩下的字節(jié)就存儲(chǔ)著字符串。 所以, 它的格式是這樣的:

其中tag占一個(gè)字節(jié), length占2個(gè)字節(jié), bytes代表存儲(chǔ)的字符串, 占length字節(jié)。所以, 如果這個(gè)CONSTANT_Utf8_info存儲(chǔ)的是字符串"Hello", 那么他的存儲(chǔ)形式是這樣的:

現(xiàn)在我們知道了CONSTANT_Utf8_info數(shù)據(jù)項(xiàng)的存儲(chǔ)形式, 那么CONSTANT_Utf8_info數(shù)據(jù)項(xiàng)都存儲(chǔ)了什么字符串呢? CONSTANT_Utf8_info可包括的字符串主要以下這些:

  • 程序中的字符串常量
  • 常量池所在當(dāng)前類(lèi)(包括接口和枚舉)的全限定名
  • 常量池所在當(dāng)前類(lèi)的直接父類(lèi)的全限定名
  • 常量池所在當(dāng)前類(lèi)型所實(shí)現(xiàn)或繼承的所有接口的全限定名
  • 常量池所在當(dāng)前類(lèi)型中所定義的字段的名稱(chēng)和描述符
  • 常量池所在當(dāng)前類(lèi)型中所定義的方法的名稱(chēng)和描述符
  • 由當(dāng)前類(lèi)所引用的類(lèi)型的全限定名
  • 由當(dāng)前類(lèi)所引用的其他類(lèi)中的字段的名稱(chēng)和描述符
  • 由當(dāng)前類(lèi)所引用的其他類(lèi)中的方法的名稱(chēng)和描述符
  • 與當(dāng)前class文件中的屬性相關(guān)的字符串, 如屬性名等

總結(jié)一下, 其中有這么五類(lèi): 程序中的字符串常量, 類(lèi)型的全限定名, 方法和字段的名稱(chēng), 方法和字段的描述符, 屬性相關(guān)字符串。 程序中的字符串常量不用多說(shuō)了, 我們經(jīng)常使用它們創(chuàng)建字符串對(duì)象, 屬性相關(guān)的字符串, 等到講到class中的屬性信息(attibute)時(shí)自會(huì)提及。 方法和字段的名稱(chēng)也不用多說(shuō)了。剩下的就是類(lèi)型的全限定名,方法和字段的描述符。還有一點(diǎn)需要說(shuō)明, 類(lèi)型的全限定名, 方法和字段的名稱(chēng),方法和字段的描述符,可以是本類(lèi)型中定義的, 也可能是本類(lèi)中引用的其他類(lèi)的。

下面我們通過(guò)一個(gè)例子來(lái)進(jìn)行說(shuō)明。 示例源碼:

package com.jg.zhang;

public class Programer extends Person {

 static String company = "CompanyA";
 
 static{
 System.out.println("staitc init");
 }
 
 
 String position;
 Computer computer;

 public Programer() {
 this.position = "engineer";
 this.computer = new Computer();
 }
 
 public void working(){
 System.out.println("coding...");
 computer.working();
 }
}

別看這個(gè)類(lèi)簡(jiǎn)單, 但是反編譯后, 它的常量池有53項(xiàng)之多。 在這53項(xiàng)常量池?cái)?shù)據(jù)項(xiàng)中, 各種類(lèi)型的數(shù)據(jù)項(xiàng)都有, 當(dāng)然也包括不少的CONSTANT_Utf8_info 。 下面只列出反編譯后常量池中的CONSTANT_Utf8_info 數(shù)據(jù)項(xiàng):

#2 = Utf8    com/jg/zhang/Programer   //當(dāng)前類(lèi)的全限定名
#4 = Utf8    com/jg/zhang/Person    //父類(lèi)的全限定名
#5 = Utf8    company       //company字段的名稱(chēng)
#6 = Utf8    Ljava/lang/String;    //company和position字段的描述符
#7 = Utf8    position      //position字段的名稱(chēng)
#8 = Utf8    computer      //computer字段的名稱(chēng)
#9 = Utf8    Lcom/jg/zhang/Computer;   //computer字段的描述符
#10 = Utf8    <clinit>      //類(lèi)初始化方法(即靜態(tài)初始化塊)的方法名
#11 = Utf8    ()V        //working方法的描述符
#12 = Utf8    Code       //Code屬性的屬性名
#14 = Utf8    CompanyA      //程序中的常量字符串
#19 = Utf8    java/lang/System    //所引用的System類(lèi)的全限定名
#21 = Utf8    out        //所引用的out字段的字段名
#22 = Utf8    Ljava/io/PrintStream;   //所引用的out字段的描述符
#24 = Utf8    staitc init      //程序中的常量字符串
#27 = Utf8    java/io/PrintStream    //所引用的PrintStream類(lèi)的全限定名
#29 = Utf8    println       //所引用的println方法的方法名
#30 = Utf8    (Ljava/lang/String;)V   //所引用的println方法的描述符
#31 = Utf8    LineNumberTable     //LineNumberTable屬性的屬性名
#32 = Utf8    LocalVariableTable    //LocalVariableTable屬性的屬性名
#33 = Utf8    <init>       //當(dāng)前類(lèi)的構(gòu)造方法的方法名
#41 = Utf8    com/jg/zhang/Computer   //所引用的Computer類(lèi)的全限定名
#45 = Utf8    this       //局部變量this的變量名
#46 = Utf8    Lcom/jg/zhang/Programer;  //局部變量this的描述符
#47 = Utf8    working       //woking方法的方法名
#49 = Utf8    coding...      //程序中的字符串常量
#52 = Utf8    SourceFile      //SourceFile屬性的屬性名
#53 = Utf8    Programer.java     //當(dāng)前類(lèi)所在的源文件的文件名

上面只列出了反編譯結(jié)果中常量池中的CONSTANT_Utf8_info數(shù)據(jù)項(xiàng)。 其中第三列不是javap反編譯的輸出結(jié)果, 而是我加上的注釋。 讀者可以對(duì)比上面的程序源碼來(lái)看一下, 這樣的話, 就可以清楚的看出, 源文件中的各種字符串, 是如何和存放到CONSTANT_Utf8_info中的。

這里要強(qiáng)調(diào)一下, 源文件中的幾乎所有可見(jiàn)的字符串都存放在CONSTANT_Utf8_info中, 其他類(lèi)型的常量池項(xiàng)只不過(guò)是對(duì)CONSTANT_Utf8_info的引用。 其他常量池項(xiàng), 把引用的CONSTANT_Utf8_info組合起來(lái), 進(jìn)而可以描述更多的信息。 下面將要介紹的CONSTANT_NameAndType_info就可以驗(yàn)證這個(gè)結(jié)論。

(2) CONSTANT_NameAndType類(lèi)型的數(shù)據(jù)項(xiàng)

常量池中的一個(gè)CONSTANT_NameAndType_info數(shù)據(jù)項(xiàng), 可以看做CONSTANT_NameAndType類(lèi)型的一個(gè)實(shí)例 。 從這個(gè)數(shù)據(jù)項(xiàng)的名稱(chēng)可以看出, 它描述了兩種信息,第一種信息是名稱(chēng)(Name), 第二種信息是類(lèi)型(Type)。 這里的名稱(chēng)是指方法的名稱(chēng)或者字段的名稱(chēng), 而Type是廣義上的類(lèi)型, 它其實(shí)描述的是字段的描述符或方法的描述符。 也就是說(shuō), 如果Name部分是一個(gè)字段名稱(chēng), 那么Type部分就是相應(yīng)字段的描述符; 如果Name部分描述的是一個(gè)方法的名稱(chēng), 那么Type部分就是對(duì)應(yīng)的方法的描述符。 也就是說(shuō), 一個(gè)CONSTANT_NameAndType_info就表示了一個(gè)方法或一個(gè)字段。 

下面先看一下CONSTANT_NameAndType_info數(shù)據(jù)項(xiàng)的存儲(chǔ)格式。 既然是常量池中的一種數(shù)據(jù)項(xiàng)類(lèi)型, 那么它的第一個(gè)字節(jié)也是tag, 它的tag值是12, 也就是說(shuō), 當(dāng)虛擬機(jī)讀到一個(gè)tag為12的常量池?cái)?shù)據(jù)項(xiàng), 就可以確定這個(gè)數(shù)據(jù)項(xiàng)是一個(gè)CONSTANT_NameAndType_info 。 tag值一下的兩個(gè)字節(jié)叫做name_index, 它指向常量池中的一個(gè)CONSTANT_Utf8_info, 這個(gè)CONSTANT_Utf8_info中存儲(chǔ)的就是方法或字段的名稱(chēng)。 name_index以后的兩個(gè)字節(jié)叫做descriptor_index, 它指向常量池中的一個(gè)CONSTANT_Utf8_info, 這個(gè)CONSTANT_Utf8_info中存儲(chǔ)的就是方法或字段的描述符。 下圖表示它的存儲(chǔ)布局:

下面舉一個(gè)實(shí)例進(jìn)行說(shuō)明, 實(shí)例的源碼為:

package com.jg.zhang;

public class Person {

 int age;

 int getAge(){
 return age;
 }
}

這個(gè)Person類(lèi)很簡(jiǎn)單, 只有一個(gè)字段age, 和一個(gè)方法getAge 。 將這段代碼使用javap工具反編譯之后, 常量池信息如下:

#1 = Class    #2    // com/jg/zhang/Person
 #2 = Utf8    com/jg/zhang/Person
 #3 = Class    #4    // java/lang/Object
 #4 = Utf8    java/lang/Object
 #5 = Utf8    age
 #6 = Utf8    I
 #7 = Utf8    <init>
 #8 = Utf8    ()V
 #9 = Utf8    Code
 #10 = Methodref   #3.#11   // java/lang/Object."<init>":()V
 #11 = NameAndType  #7:#8   // "<init>":()V
 #12 = Utf8    LineNumberTable
 #13 = Utf8    LocalVariableTable
 #14 = Utf8    this
 #15 = Utf8    Lcom/jg/zhang/Person;
 #16 = Utf8    getAge
 #17 = Utf8    ()I
 #18 = Fieldref   #1.#19   // com/jg/zhang/Person.age:I
 #19 = NameAndType  #5:#6   // age:I
 #20 = Utf8    SourceFile
 #21 = Utf8    Person.java

常量池一共有21項(xiàng), 我們可以看到, 一共有兩個(gè)CONSTANT_NameAndType_info 數(shù)據(jù)項(xiàng), 分別是第#11項(xiàng)和第#19項(xiàng), 其中第#11項(xiàng)的CONSTANT_NameAndType_info又引用了常量池中的第#7項(xiàng)和第#8項(xiàng), 被引用的這兩項(xiàng)都是CONSTANT_Utf8_info , 它們中存儲(chǔ)的字符串常量值分別是 <init> 和 ()V。 其實(shí)他們加起來(lái)表示的就是父類(lèi)Object的構(gòu)造方法。 那么這里為什么會(huì)是父類(lèi)Object的構(gòu)造方法而不是本類(lèi)的構(gòu)造方法呢? 這是因?yàn)轭?lèi)中定義的方法如果不被引用(也就是說(shuō)在當(dāng)前類(lèi)中不被調(diào)用), 那么常量池中是不會(huì)有相應(yīng)的 CONSTANT_NameAndType_info 與之對(duì)應(yīng)的, 只有引用了一個(gè)方法, 才有相應(yīng)的CONSTANT_NameAndType_info 與之對(duì)應(yīng)。 這也是為什么說(shuō)CONSTANT_NameAndType_info 是方法的符號(hào)引用的一部分的原因。 (這里提到一個(gè)新的概念, 叫做方法的符號(hào)引用, 這個(gè)概念會(huì)在后面的博客中進(jìn)行講解) 可以看到, 在源碼存在兩個(gè)方法, 分別是編譯器默認(rèn)添加的構(gòu)造方法和我們自己定義的getAge方法, 因?yàn)椴](méi)有在源碼中顯示的調(diào)用這兩個(gè)方法,所以在常量池中并不存在和這兩個(gè)方法相對(duì)應(yīng)的CONSTANT_NameAndType_info 。  之所以會(huì)存在父類(lèi)Object的構(gòu)造方法對(duì)應(yīng)的CONSTANT_NameAndType_info , 是因?yàn)樽宇?lèi)構(gòu)造方法中會(huì)默認(rèn)調(diào)用父類(lèi)的無(wú)參數(shù)構(gòu)造方法。 我們將常量中的其他信息去掉, 可以看得更直觀:

下面講解常量池第#19項(xiàng)的CONSTANT_NameAndType_info , 它引用了常量池第#5項(xiàng)和第#6項(xiàng), 這兩項(xiàng)也是CONSTANT_Utf8_info 項(xiàng), 其中存儲(chǔ)的字符串分別是age和I, 其中age是源碼中字段age的字段名, I是age字段的描述符。 所以這個(gè)CONSTANT_NameAndType_info 就表示對(duì)本類(lèi)中的字段age的引用。 除去常量池中的其他信息, 可以看得更直觀:

和方法相同, 只定義一個(gè)字段而不引用它(在源碼中表現(xiàn)為不訪問(wèn)這個(gè)變量), 那么在常量池中也不會(huì)存在和該字段相對(duì)應(yīng)的CONSTANT_NameAndType_info 項(xiàng)。這也是為什么說(shuō)CONSTANT_NameAndType_info作為字段符號(hào)引用的一部分的原因。 (這里提到一個(gè)新的概念, 叫做字段的符號(hào)引用, 這個(gè)概念會(huì)在后面的博客中進(jìn)行講解) 在本例中之所以會(huì)出現(xiàn)這個(gè)CONSTANT_NameAndType_info , 是因?yàn)樵谠创a的getAge方法中訪問(wèn)了這個(gè)字段:

int getAge(){ 
 return age; 
} 

下面給出這兩個(gè)CONSTANT_NameAndType_info真實(shí)的內(nèi)存布局圖:

和Object構(gòu)造方法相關(guān)的CONSTANT_NameAndType_info的示意圖:

和age字段相關(guān)的CONSTANT_NameAndType_info示意圖:

這兩張圖能夠很好的反映出CONSTANT_NameAndType_info和CONSTANT_Utf8_info 這兩種常量池?cái)?shù)據(jù)項(xiàng)的數(shù)據(jù)存儲(chǔ)方式, 也能夠真實(shí)的反應(yīng)CONSTANT_NameAndType_info和CONSTANT_Utf8_info 的引用關(guān)系。 

總結(jié)

在本文中我們主要介紹了常量池中的兩種數(shù)據(jù)項(xiàng):CONSTANT_NameAndType_info和CONSTANT_Utf8_info 。其中CONSTANT_Utf8_info存儲(chǔ)的是源文件中的各種字符串,而CONSTANT_NameAndType_info表述的是源文件中對(duì)一個(gè)字段或方法的符號(hào)引用的一部分(即 方法名加方法描述符,或者是 字段名加字段描述符)。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java之鍵盤(pán)輸入語(yǔ)句Scanner解讀

    Java之鍵盤(pán)輸入語(yǔ)句Scanner解讀

    這篇文章主要介紹了Java之鍵盤(pán)輸入語(yǔ)句Scanner解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Java?volatile關(guān)鍵字特性講解下篇

    Java?volatile關(guān)鍵字特性講解下篇

    JMM要求保證可見(jiàn)性、原子性、有序性,volatile可以保證其中的兩個(gè),本篇文章具體驗(yàn)證volatile的可見(jiàn)性,不原子性和禁重排,同時(shí)解決volatile的不保證原子性,讓代碼具有原子性
    2022-12-12
  • JAVA異常分類(lèi)和處理解析

    JAVA異常分類(lèi)和處理解析

    這篇文章主要介紹了JAVA異常分類(lèi)和處理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • Java使用poi做加自定義注解實(shí)現(xiàn)對(duì)象與Excel相互轉(zhuǎn)換

    Java使用poi做加自定義注解實(shí)現(xiàn)對(duì)象與Excel相互轉(zhuǎn)換

    這篇文章主要介紹了Java使用poi做加自定義注解實(shí)現(xiàn)對(duì)象與Excel相互轉(zhuǎn)換,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • java基于Apache FTP點(diǎn)斷續(xù)傳的文件上傳和下載

    java基于Apache FTP點(diǎn)斷續(xù)傳的文件上傳和下載

    本篇文章主要介紹了java基于Apache FTP點(diǎn)斷續(xù)傳的文件上傳和下載,利用FTP實(shí)現(xiàn)文件的上傳和下載,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2016-11-11
  • SpringBoot使用Guava實(shí)現(xiàn)日志脫敏的示例代碼

    SpringBoot使用Guava實(shí)現(xiàn)日志脫敏的示例代碼

    本文主要介紹了SpringBoot使用Guava實(shí)現(xiàn)日志脫敏的示例代碼,使用Guava中的Strings、Maps和CharMatcher類(lèi)來(lái)進(jìn)行日志脫敏,保護(hù)敏感數(shù)據(jù)的安全,感興趣的可以了解一下
    2024-01-01
  • idea中導(dǎo)入別人的springboot項(xiàng)目的方法(圖文)

    idea中導(dǎo)入別人的springboot項(xiàng)目的方法(圖文)

    這篇文章主要介紹了idea中導(dǎo)入別人的springboot項(xiàng)目的方法(圖文),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • java圖形化界面實(shí)現(xiàn)登錄窗口

    java圖形化界面實(shí)現(xiàn)登錄窗口

    這篇文章主要為大家詳細(xì)介紹了java圖形化界面實(shí)現(xiàn)登錄窗口,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • 解決Java中properties文件編碼問(wèn)題

    解決Java中properties文件編碼問(wèn)題

    大家好,本篇文章主要講的是解決Java中properties文件編碼問(wèn)題,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-02-02
  • java實(shí)現(xiàn)Spring在XML配置java類(lèi)的方法

    java實(shí)現(xiàn)Spring在XML配置java類(lèi)的方法

    下面小編就為大家?guī)?lái)一篇java實(shí)現(xiàn)Spring在XML配置java類(lèi)的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-11-11

最新評(píng)論