您好,登錄后才能下訂單哦!
深入淺析Java中 class文件的數據類型?相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
CONSTANT_Integer_info
一個常量池中的CONSTANT_Integer_info數據項, 可以看做是CONSTANT_Integer類型的一個實例。 它存儲的是源文件中出現的int型數據的值。 同樣, 作為常量池中的一種數據類型, 它的第一個字節也是一個tag值, 它的tag值為3, 也就是說, 當虛擬機讀到一個tag值為3的數據項時, 就知道這個數據項是一個CONSTANT_Integer_info, 它存儲的是int型數值的值。 緊挨著tag的下面4個字節叫做bytes, 就是int型數值的整型值。 它的內存布局如下:
下面以示例代碼進行說明, 示例代碼如下:
package com.bjpowernode.test; public class TestInt { void printInt(){ System.out.println(65535); } }
將上面的類生成的class文件反編譯:
1.D:\Workspace\AndroidWorkspace\BlogTest\bin>javap -v -c -classpath . com.bjpowernode.test.TestInt
下面列出反編譯的結果, 由于反編譯結果較長, 我們省略了大部分信息:
.................. .................. Constant pool: .................. .................. #21 = Integer 65535 .................. .................. { .................. .................. void printInt(); flags: Code: stack=2, locals=1, args_size=1 0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #21 // int 65535 5: invokevirtual #22 // Method java/io/PrintStream.println:(I)V 8: return LineNumberTable: line 6: 0 line 7: 8 LocalVariableTable: Start Length Slot Name Signature 0 9 0 this Lcom/bjpowernode/test/TestInt; }
上面的輸出結果中, 保留了printInt方法的反編譯結果, 并且保留了常量池中的第21項。 首先看printInt方法反編譯結果中的索引為3 的字節碼指令:
1.3: ldc #21 // int 65535
這條ldc指令, 引用了常量池中的第21項, 而第21項是一個CONSTANT_Integer_info, 并且這個CONSTANT_Integer_info存儲的整型值為65535 。
CONSTANT_Float_info
一個常量池中的CONSTANT_Float_info數據項, 可以看做是CONSTANT_Float類型的一個實例。 它存儲的是源文件中出現的float型數據的值。 同樣, 作為常量池中的一種數據類型, 它的第一個字節也是一個tag值, 它的tag值為4, 也就是說, 當虛擬機讀到一個tag值為4的數據項時, 就知道這個數據項是一個CONSTANT_Float_info, 并且知道它存儲的是float型數值。 緊挨著tag的下面4個字節叫做bytes, 就是float型的數值。 它的內存布局如下:
舉例說明, 如果源文件中的一句代碼使用了一個float值, 如下所示:
void printFloat(){ System.out.println(1234.5f); }
那么在這個類的常量池中就會有一個CONSTANT_Float_info與之相對應, 這個CONSTANT_Float_info的形式如下:
代碼反編譯結果如下:
Constant pool: ............ ............ #29 = Float 1234.5f ........... ........... { ............ ............ void printFloat(); flags: Code: stack=2, locals=1, args_size=1 0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #29 // float 1234.5f 5: invokevirtual #30 // Method java/io/PrintStream.println:(F)V 8: return LineNumberTable: line 10: 0 line 11: 8 LocalVariableTable: Start Length Slot Name Signature 0 9 0 this Lcom/bjpowernode/test/TestInt; }
CONSTANT_Long_info
一個常量池中的CONSTANT_Long_info數據項, 可以看做是CONSTANT_Long類型的一個實例。 它存儲的是源文件中出現的long型數據的值。 同樣, 作為常量池中的一種數據類型, 它的第一個字節也是一個tag值, 它的tag值為5, 也就是說, 當虛擬機讀到一個tag值為5的數據項時, 就知道這個數據項是一個CONSTANT_Long_info, 并且知道它存儲的是long型數值。 緊挨著tag的下面8個字節叫做bytes, 就是long型的數值。 它的內存布局如下:
舉例說明, 如果源文件中的一句代碼使用了一個long型的數值, 如下所示:
void printLong(){ System.out.println(123456L); }
那么在這個類的常量池中就會有一個CONSTANT_Long_info與之相對應, 這個CONSTANT_Long_info的形式如下:
代碼反編譯結果為:
Constant pool: ............. ............. #21 = Long 123456l ............. ............. { .............. .............. void printLong(); flags: Code: stack=3, locals=1, args_size=1 0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc2_w #21 // long 123456l 6: invokevirtual #23 // Method java/io/PrintStream.println:(J)V 9: return LineNumberTable: line 7: 0 line 8: 9 LocalVariableTable: Start Length Slot Name Signature 0 10 0 this Lcom/bjpowernode/test/TestInt; }
CONSTANT_Double_info
一個常量池中的CONSTANT_Double_info數據項, 可以看做是CONSTANT_Double類型的一個實例。 它存儲的是源文件中出現的double型數據的值。 同樣, 作為常量池中的一種數據類型, 它的第一個字節也是一個tag值, 它的tag值為6, 也就是說, 當虛擬機讀到一個tag值為6的數據項時, 就知道這個數據項是一個CONSTANT_Double_info, 并且知道它存儲的是double型數值。 緊挨著tag的下面8個字節叫做bytes, 就是double型的數值。 它的內存布局如下:
舉例說明, 如果源文件中的一句代碼使用了一個double型的數值, 如下所示:
void printDouble(){ System.out.println(123456D); }
那么在這個類的常量池中就會有一個CONSTANT_Double_info與之相對應, 這個CONSTANT_Double_info的形式如下:
代碼反編譯結果為:
Constant pool: ............ ............ #21 = Double 123456.0d ............ ............ { ............. ............. void printDouble(); flags: Code: stack=3, locals=1, args_size=1 0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc2_w #21 // double 123456.0d 6: invokevirtual #23 // Method java/io/PrintStream.println:(D)V 9: return LineNumberTable: line 7: 0 line 8: 9 LocalVariableTable: Start Length Slot Name Signature 0 10 0 this Lcom/bjpowernode/test/TestInt; }
CONSTANT_String_info
在常量池中, 一個CONSTANT_String_info數據項, 是CONSTANT_String類型的一個實例。 它的作用是存儲文字字符串, 可以把他看做是一個存在于class文件中的字符串對象。 同樣, 它的第一個字節是tag值, 值為8 , 也就是說, 虛擬機訪問一個數據項時, 判斷tag值為8 , 就說明訪問的數據項是一個CONSTANT_String_info 。 緊挨著tag的后兩個字節是一個叫做string_index的常量池引用, 它指向一個CONSTANT_Utf8_info, 這個CONSTANT_Utf8_info存放的才是字符串的字面量。 它的內存布局如下:
舉例說明, 如果源文件中的一句代碼使用了一個字符串常量, 如下所示:
void printStrng(){ System.out.println("abcdef"); }
那么在這個類的常量池中就會有一個CONSTANT_String_info與之相對應, 反編譯結果如下:
Constant pool: ............ ............ #21 = String #22 // abcdef #22 = Utf8 abcdef ............ ............. { ............. ............. void printStrng(); flags: Code: stack=2, locals=1, args_size=1 0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #21 // String abcdef 5: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 7: 0 line 8: 8 LocalVariableTable: Start Length Slot Name Signature 0 9 0 this Lcom/bjpowernode/test/TestInt; }
其中printString方法中索引為3的字節碼指令ldc引用常量池中的第21項, 第21項是一個CONSTANT_String_info, 這個位于第21項的CONSTANT_String_info又引用了常量池的第22項, 第22項是一個CONSTANT_Utf8_info, 這個CONSTANT_Utf8_info中存儲的字符串是 abcdef 。 引用關系的內存布局如下:
總結
最后總結一下, 本文主要講解了常量池中的五中數據項, 分別為CONSTANT_Integer_info, CONSTANT_Float_info, CONSTANT_Long_info, CONSTANT_Double_info 和CONSTANT_String_info 。 這幾種常量池數據項都是直接存儲的常量值,而不是符號引用。 這里又一次出現了符號引用的概念, 這個概念將會在下一篇博客中詳細講解, 因為下一篇博客要介紹的剩下的四種常量池數據項, 都是符號引用, 這四種表示符號引用的數據項又會直接或間接引用上篇文章中介紹的CONSTANT_NameAndType_info和CONSTANT_Utf8_info, 所以說CONSTANT_NameAndType_info是符號引用的一部分。
看完上述內容,你們掌握深入淺析Java中 class文件的數據類型的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。