国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java class文件格式之常量池_動力節(jié)點Java學院整理

Java class文件格式之常量池_動力節(jié)點Java學院整理

2020-11-17 11:03動力節(jié)點 Java教程

這篇文章主要為大家詳細介紹了Java class文件格式之常量池的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下

常量池中各數(shù)據(jù)項類型詳解

常量池中的數(shù)據(jù)項是通過索引來引用的, 常量池中的各個數(shù)據(jù)項之間也會相互引用。在這11中常量池數(shù)據(jù)項類型中, 有兩種比較基礎, 之所以說它們基礎, 是因為這兩種類型的數(shù)據(jù)項會被其他類型的數(shù)據(jù)項引用。 這兩種數(shù)據(jù)類型就是constant_utf8 和 constant_nameandtype , 其中constant_nameandtype類型的數(shù)據(jù)項(constant_nameandtype_info)也會引用constant_utf8類型的數(shù)據(jù)項(constant_utf8_info) 。 與其他介紹常量池的書籍或其他資料不同, 本著循序漸進和先后分明的原則, 我們首先對這兩種比較基本的類型的數(shù)據(jù)項進行介紹, 然后再依次介紹其他9中數(shù)據(jù)項。 

(1) constant_utf8_info

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

 Java class文件格式之常量池_動力節(jié)點Java學院整理

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

 Java class文件格式之常量池_動力節(jié)點Java學院整理

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

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

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

下面我們通過一個例子來進行說明。 示例源碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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();
 }
}

別看這個類簡單, 但是反編譯后, 它的常量池有53項之多。 在這53項常量池數(shù)據(jù)項中, 各種類型的數(shù)據(jù)項都有, 當然也包括不少的constant_utf8_info 。 下面只列出反編譯后常量池中的constant_utf8_info 數(shù)據(jù)項:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#2 = utf8    com/jg/zhang/programer   //當前類的全限定名
#4 = utf8    com/jg/zhang/person    //父類的全限定名
#5 = utf8    company       //company字段的名稱
#6 = utf8    ljava/lang/string;    //company和position字段的描述符
#7 = utf8    position      //position字段的名稱
#8 = utf8    computer      //computer字段的名稱
#9 = utf8    lcom/jg/zhang/computer;   //computer字段的描述符
#10 = utf8    <clinit>      //類初始化方法(即靜態(tài)初始化塊)的方法名
#11 = utf8    ()v        //working方法的描述符
#12 = utf8    code       //code屬性的屬性名
#14 = utf8    companya      //程序中的常量字符串
#19 = utf8    java/lang/system    //所引用的system類的全限定名
#21 = utf8    out        //所引用的out字段的字段名
#22 = utf8    ljava/io/printstream;   //所引用的out字段的描述符
#24 = utf8    staitc init      //程序中的常量字符串
#27 = utf8    java/io/printstream    //所引用的printstream類的全限定名
#29 = utf8    println       //所引用的println方法的方法名
#30 = utf8    (ljava/lang/string;)v   //所引用的println方法的描述符
#31 = utf8    linenumbertable     //linenumbertable屬性的屬性名
#32 = utf8    localvariabletable    //localvariabletable屬性的屬性名
#33 = utf8    <init>       //當前類的構造方法的方法名
#41 = utf8    com/jg/zhang/computer   //所引用的computer類的全限定名
#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     //當前類所在的源文件的文件名

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

這里要強調(diào)一下, 源文件中的幾乎所有可見的字符串都存放在constant_utf8_info中, 其他類型的常量池項只不過是對constant_utf8_info的引用。 其他常量池項, 把引用的constant_utf8_info組合起來, 進而可以描述更多的信息。 下面將要介紹的constant_nameandtype_info就可以驗證這個結論。

(2) constant_nameandtype類型的數(shù)據(jù)項

常量池中的一個constant_nameandtype_info數(shù)據(jù)項, 可以看做constant_nameandtype類型的一個實例 。 從這個數(shù)據(jù)項的名稱可以看出, 它描述了兩種信息,第一種信息是名稱(name), 第二種信息是類型(type) 。 這里的名稱是指方法的名稱或者字段的名稱, 而type是廣義上的類型, 它其實描述的是字段的描述符或方法的描述符。 也就是說, 如果name部分是一個字段名稱, 那么type部分就是相應字段的描述符; 如果name部分描述的是一個方法的名稱, 那么type部分就是對應的方法的描述符。 也就是說, 一個constant_nameandtype_info就表示了一個方法或一個字段。 

下面先看一下constant_nameandtype_info數(shù)據(jù)項的存儲格式。 既然是常量池中的一種數(shù)據(jù)項類型, 那么它的第一個字節(jié)也是tag, 它的tag值是12, 也就是說, 當虛擬機讀到一個tag為12的常量池數(shù)據(jù)項, 就可以確定這個數(shù)據(jù)項是一個constant_nameandtype_info 。 tag值一下的兩個字節(jié)叫做name_index, 它指向常量池中的一個constant_utf8_info, 這個constant_utf8_info中存儲的就是方法或字段的名稱。 name_index以后的兩個字節(jié)叫做descriptor_index, 它指向常量池中的一個constant_utf8_info, 這個constant_utf8_info中存儲的就是方法或字段的描述符。 下圖表示它的存儲布局:

Java class文件格式之常量池_動力節(jié)點Java學院整理

下面舉一個實例進行說明, 實例的源碼為:

?
1
2
3
4
5
6
7
8
9
10
package com.jg.zhang;
 
public class person {
 
 int age;
 
 int getage(){
 return age;
 }
}

這個person類很簡單, 只有一個字段age, 和一個方法getage 。 將這段代碼使用javap工具反編譯之后, 常量池信息如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#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項, 我們可以看到, 一共有兩個constant_nameandtype_info 數(shù)據(jù)項, 分別是第#11項和第#19項, 其中第#11項的constant_nameandtype_info又引用了常量池中的第#7項和第#8項, 被引用的這兩項都是constant_utf8_info , 它們中存儲的字符串常量值分別是 <init> 和 ()v。 其實他們加起來表示的就是父類object的構造方法。 那么這里為什么會是父類object的構造方法而不是本類的構造方法呢? 這是因為類中定義的方法如果不被引用(也就是說在當前類中不被調(diào)用), 那么常量池中是不會有相應的 constant_nameandtype_info 與之對應的, 只有引用了一個方法, 才有相應的constant_nameandtype_info 與之對應。 這也是為什么說constant_nameandtype_info 是方法的符號引用的一部分的原因。 (這里提到一個新的概念, 叫做方法的符號引用, 這個概念會在后面的博客中進行講解) 可以看到, 在源碼存在兩個方法, 分別是編譯器默認添加的構造方法和我們自己定義的getage方法, 因為并沒有在源碼中顯示的調(diào)用這兩個方法,所以在常量池中并不存在和這兩個方法相對應的constant_nameandtype_info 。  之所以會存在父類object的構造方法對應的constant_nameandtype_info , 是因為子類構造方法中會默認調(diào)用父類的無參數(shù)構造方法。 我們將常量中的其他信息去掉, 可以看得更直觀:

Java class文件格式之常量池_動力節(jié)點Java學院整理

下面講解常量池第#19項的constant_nameandtype_info , 它引用了常量池第#5項和第#6項, 這兩項也是constant_utf8_info 項, 其中存儲的字符串分別是age和i, 其中age是源碼中字段age的字段名, i是age字段的描述符。 所以這個constant_nameandtype_info 就表示對本類中的字段age的引用。 除去常量池中的其他信息, 可以看得更直觀:

Java class文件格式之常量池_動力節(jié)點Java學院整理

和方法相同, 只定義一個字段而不引用它(在源碼中表現(xiàn)為不訪問這個變量), 那么在常量池中也不會存在和該字段相對應的constant_nameandtype_info 項。這也是為什么說constant_nameandtype_info作為字段符號引用的一部分的原因。 (這里提到一個新的概念, 叫做字段的符號引用, 這個概念會在后面的博客中進行講解) 在本例中之所以會出現(xiàn)這個constant_nameandtype_info , 是因為在源碼的getage方法中訪問了這個字段:

?
1
2
3
int getage(){
 return age;
}

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

和object構造方法相關的constant_nameandtype_info的示意圖:

Java class文件格式之常量池_動力節(jié)點Java學院整理

和age字段相關的constant_nameandtype_info示意圖:

Java class文件格式之常量池_動力節(jié)點Java學院整理

這兩張圖能夠很好的反映出constant_nameandtype_info和constant_utf8_info 這兩種常量池數(shù)據(jù)項的數(shù)據(jù)存儲方式, 也能夠真實的反應constant_nameandtype_info和constant_utf8_info 的引用關系。 

總結

在本文中我們主要介紹了常量池中的兩種數(shù)據(jù)項: constant_nameandtype_info 和 constant_utf8_info  。 其中constant_utf8_info存儲的是源文件中的各種字符串, 而constant_nameandtype_info表述的是源文件中對一個字段或方法的符號引用的一部分(即 方法名加方法描述符, 或者是 字段名加字段描述符)。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 一级黄色毛片免费观看 | 国产在线观看一区二区三区 | 国产精品一区二区不卡 | 综合久久99 | 青青操av在线 | 日韩av免费在线观看 | 精品毛片| 欧美成人免费在线观看 | 国产在线小视频 | 在线观看亚洲专区 | 青青国产视频 | 久草中文在线 | 亚洲免费在线 | 波多野结衣中文字幕一区二区三区 | 欧美激情一区二区三级高清视频 | 国产黄色av | a久久| 日韩在线视频中文字幕 | 亚洲乱码国产乱码精品精软件 | 免费成人在线视频观看 | 中文字幕一级毛片 | 2018自拍偷拍 | 成人在线视频免费观看 | 国偷自产一区二区免费视频 | 精品无人乱码一区二区三区的优势 | 搞黄视频在线观看 | 免费看国产片在线观看 | 激情综合网激情 | 成人深夜在线观看 | 久久综合久色欧美综合狠狠 | 欧美顶级毛片在线播放 | 天堂一区二区三区在线 | 国产高清视频一区 | 精品久久在线 | 午夜视频在线观看视频 | 色综合欧美| 亚洲精品综合中文字幕 | 香蕉久久久久久 | 久久精品视频网站 | 久久久国产视频 | 日韩福利在线 |