欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談JVM之java class文件的密碼本

 更新時(shí)間:2021年06月02日 14:49:24   作者:flydean  
一切的一切都是從javac開始的。從那一刻開始,java文件就從我們?nèi)庋劭煞直娴奈谋疚募兂闪死浔亩M(jìn)制文件。變成了二進(jìn)制文件是不是意味著我們無法再深入的去了解java class文件了呢?答案是否定的。本文將詳細(xì)介紹JVM之java class文件的密碼本。

簡(jiǎn)介

機(jī)器可以讀,人為什么不能讀?只要我們掌握java class文件的密碼表,我們可以把二進(jìn)制轉(zhuǎn)成十六進(jìn)制,將十六進(jìn)制和我們的密碼表進(jìn)行對(duì)比,就可以輕松的解密了。

下面,讓我們開始這個(gè)激動(dòng)人心的過程吧。

一個(gè)簡(jiǎn)單的class

為了深入理解java class的含義,我們首先需要定義一個(gè)class類:

public class JavaClassUsage {

    private int age=18;

    public void inc(int number){
        this.age=this.age+ number;
    }
}

很簡(jiǎn)單的類,我想不會(huì)有比它更簡(jiǎn)單的類了。

在上面的類中,我們定義了一個(gè)age字段和一個(gè)inc的方法。

接下來我們使用javac來進(jìn)行編譯。

IDEA有沒有?直接打開編譯后的class文件,你會(huì)看到什么?

沒錯(cuò),是反編譯過來的java代碼。但是這次我們需要深入了解的是class文件,于是我們可以選擇 view->Show Bytecode:

當(dāng)然,還是少不了最質(zhì)樸的javap命令:

 javap -verbose JavaClassUsage

對(duì)比會(huì)發(fā)現(xiàn),其實(shí)javap展示的更清晰一些,我們暫時(shí)選用javap的結(jié)果。

編譯的class文件有點(diǎn)長(zhǎng),我一度有點(diǎn)不想都列出來,但是又一想只有對(duì)才能講述得更清楚,還是貼在下面:

public class com.flydean.JavaClassUsage

  minor version: 0

  major version: 58

  flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V

   #2 = Class              #4             // java/lang/Object

   #3 = NameAndType        #5:#6          // "<init>":()V

   #4 = Utf8               java/lang/Object

   #5 = Utf8               <init>

   #6 = Utf8               ()V

   #7 = Fieldref           #8.#9          // com/flydean/JavaClassUsage.age:I

   #8 = Class              #10            // com/flydean/JavaClassUsage

   #9 = NameAndType        #11:#12        // age:I

  #10 = Utf8               com/flydean/JavaClassUsage

  #11 = Utf8               age

  #12 = Utf8               I

  #13 = Utf8               Code

  #14 = Utf8               LineNumberTable

  #15 = Utf8               LocalVariableTable

  #16 = Utf8               this

  #17 = Utf8               Lcom/flydean/JavaClassUsage;

  #18 = Utf8               inc

  #19 = Utf8               (I)V

  #20 = Utf8               number

  #21 = Utf8               SourceFile

  #22 = Utf8               JavaClassUsage.java

{

  public com.flydean.JavaClassUsage();

    descriptor: ()V

    flags: ACC_PUBLIC

    Code:

      stack=2, locals=1, args_size=1

         0: aload_0

         1: invokespecial #1                  // Method java/lang/Object."<init>":()V

         4: aload_0

         5: bipush        18

         7: putfield      #7                  // Field age:I

        10: return

      LineNumberTable:

        line 7: 0

        line 9: 4

      LocalVariableTable:

        Start  Length  Slot  Name   Signature

            0      11     0  this   Lcom/flydean/JavaClassUsage;

  public void inc(int);

    descriptor: (I)V

    flags: ACC_PUBLIC

    Code:

      stack=3, locals=2, args_size=2

         0: aload_0

         1: aload_0

         2: getfield      #7                  // Field age:I

         5: iload_1

         6: iadd

         7: putfield      #7                  // Field age:I

        10: return

      LineNumberTable:

        line 12: 0

        line 13: 10

      LocalVariableTable:

        Start  Length  Slot  Name   Signature

            0      11     0  this   Lcom/flydean/JavaClassUsage;

            0      11     1 number   I

}

SourceFile: "JavaClassUsage.java"

ClassFile的二進(jìn)制文件

慢著,上面javap的結(jié)果好像并不是二進(jìn)制文件!

對(duì)的,javap是對(duì)二進(jìn)制文件進(jìn)行了解析,方便程序員閱讀。如果你真的想直面最最底層的機(jī)器代碼,就直接用支持16進(jìn)制的文本編譯器把編譯好的class文件打開吧。

你準(zhǔn)備好了嗎?來吧,展示吧!

上圖左邊是16進(jìn)制的class文件代碼,右邊是對(duì)16進(jìn)制文件的適當(dāng)解析。大家可以隱約的看到一點(diǎn)點(diǎn)熟悉的內(nèi)容。

是的,沒錯(cuò),你會(huì)讀機(jī)器語言了!

class文件的密碼本

如果你要了解class文件的結(jié)構(gòu),你需要這個(gè)密碼本。

如果你想解析class文件,你需要這個(gè)密碼本。

學(xué)好這個(gè)密碼本,走遍天下都......沒啥用!

下面就是密碼本,也就是classFile的結(jié)構(gòu)。

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

其中u2,u4表示的是無符號(hào)的兩個(gè)字節(jié),無符號(hào)的4個(gè)字節(jié)。

java class文件就是按照上面的格式排列下來的,按照這個(gè)格式,我們可以自己實(shí)現(xiàn)一個(gè)反編譯器(大家有興趣的話,可以自行研究)。

我們對(duì)比著上面的二進(jìn)制文件一個(gè)一個(gè)的來理解。

magic

首先,class文件的前4個(gè)字節(jié)叫做magic word。

看一下十六進(jìn)制的第一行的前4個(gè)字節(jié):

CA FE BA BE 00 00 00 3A 00 17 0A 00 02 00 03 07 

0xCAFEBABE就是magic word。所有的java class文件都是以這4個(gè)字節(jié)開頭的。

來一杯咖啡吧,baby!

多么有詩意的畫面。

version

這兩個(gè)version要連著講,一個(gè)是主版本號(hào),一個(gè)是次版本號(hào)。

00 00 00 3A

對(duì)比一下上面的表格,我們的主版本號(hào)是3A=58,也就是我們使用的是JDK14版本。

常量池

接下來是常量池。

首先是兩個(gè)字節(jié)的constant_pool_count。對(duì)比一下,constant_pool_count的值是:

00 17

換算成十進(jìn)制就是23。也就是說常量池的大小是23-1=22。

這里有兩點(diǎn)要注意,第一點(diǎn),常量池?cái)?shù)組的index是從1開始到constant_pool_count-1結(jié)束。

第二點(diǎn),常量池?cái)?shù)組的第0位是作為一個(gè)保留位,表示“不引用任何常量池項(xiàng)目”,為某些特殊的情況下使用。

接下來是不定長(zhǎng)度的cp_info:constant_pool[constant_pool_count-1]常量池?cái)?shù)組。

常量池?cái)?shù)組中存了些什么東西呢?

字符串常量,類和接口名字,字段名,和其他一些在class中引用的常量。

具體的constant_pool中存儲(chǔ)的常量類型有下面幾種:

每個(gè)常量都是以一個(gè)tag開頭的。用來告訴JVM,這個(gè)到底是一個(gè)什么常量。

好了,我們對(duì)比著來看一下。在constant_pool_count之后,我們?cè)偃∫徊糠?6進(jìn)制數(shù)據(jù):

上面我們講到了17是常量池的個(gè)數(shù),接下來就是常量數(shù)組。

0A 00 02 00 03

首先第一個(gè)字節(jié)是常量的tag, 0A=10,對(duì)比一下上面的表格,10表示的是CONSTANT_Methodref方法引用。

CONSTANT_Methodref又是一個(gè)結(jié)構(gòu)體,我們?cè)倏匆幌路椒ㄒ玫亩x:

CONSTANT_Methodref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}

從上面的定義我們可以看出,CONSTANT_Methodref是由三部分組成的,第一部分是一個(gè)字節(jié)的tag,也就是上面的0A。

第二部分是2個(gè)字節(jié)的class_index,表示的是類在常量池中的index。

第三部分是2個(gè)字節(jié)的name_and_type_index,表示的是方法的名字和類型在常量池中的index。

先看class_index,0002=2。

常量池的第一個(gè)元素我們已經(jīng)找到了就是CONSTANT_Methodref,第二個(gè)元素就是跟在CONSTANT_Methodref后面的部分,我們看下是什么:

07 00 04

一樣的解析步驟,07=7,查表,表示的是CONSTANT_Class。

我們?cè)倏聪翪ONSTANT_Class的定義:

CONSTANT_Class_info {
    u1 tag;
    u2 name_index;
}

可以看到CONSTANT_Class占用3個(gè)字節(jié),第一個(gè)字節(jié)是tag,后面兩個(gè)字節(jié)是name在常量池中的索引。

00 04 = 4, 表示name在常量池中的索引是4。

然后我們就這樣一路找下去,就得到了所有常量池中常量的信息。

這樣找起來,眼睛都花了,有沒有什么簡(jiǎn)單的辦法呢?

當(dāng)然有,就是上面的javap -version, 我們?cè)倩仡櫼幌螺敵鼋Y(jié)果中的常量池部分:

Constant pool:

   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V

   #2 = Class              #4             // java/lang/Object

   #3 = NameAndType        #5:#6          // "<init>":()V

   #4 = Utf8               java/lang/Object

   #5 = Utf8               <init>

   #6 = Utf8               ()V

   #7 = Fieldref           #8.#9          // com/flydean/JavaClassUsage.age:I

   #8 = Class              #10            // com/flydean/JavaClassUsage

   #9 = NameAndType        #11:#12        // age:I

  #10 = Utf8               com/flydean/JavaClassUsage

  #11 = Utf8               age

  #12 = Utf8               I

  #13 = Utf8               Code

  #14 = Utf8               LineNumberTable

  #15 = Utf8               LocalVariableTable

  #16 = Utf8               this

  #17 = Utf8               Lcom/flydean/JavaClassUsage;

  #18 = Utf8               inc

  #19 = Utf8               (I)V

  #20 = Utf8               number

  #21 = Utf8               SourceFile

  #22 = Utf8               JavaClassUsage.java

以第一行為例,直接告訴你常量池中第一個(gè)index的類型是Methodref,它的classref是index=2,它的NameAndType是index=3。

并且直接在后面展示出了具體的值。

描述符

且慢,在常量池中我好像看到了一些不一樣的東西,這些I,L是什么東西?

這些叫做字段描述符:

上圖是他們的各項(xiàng)含義。除了8大基礎(chǔ)類型,還有2個(gè)引用類型,分別是對(duì)象的實(shí)例,和數(shù)組。

access_flags

常量池后面就是access_flags:訪問描述符,表示的是這個(gè)class或者接口的訪問權(quán)限。

先上密碼表:

再找一下我們16進(jìn)制的access_flag:

沒錯(cuò),就是00 21。 參照上面的表格,好像沒有21,但是別怕:

21是ACC_PUBLIC和ACC_SUPER的并集。表示它有兩個(gè)access權(quán)限。

this_class和super_class

接下來是this class和super class的名字,他們都是對(duì)常量池的引用。

00 08 00 02

this class的常量池index=8, super class的常量池index=2。

看一下2和8都代表什么:

#2 = Class              #4             // java/lang/Object

#8 = Class              #10            // com/flydean/JavaClassUsage

沒錯(cuò),JavaClassUsage的父類是Object。

大家知道為什么java只能單繼承了嗎?因?yàn)閏lass文件里面只有一個(gè)u2的位置,放不下了!

interfaces_count和interfaces[]

接下來就是接口的數(shù)目和接口的具體信息數(shù)組了。

00 00

我們沒有實(shí)現(xiàn)任何接口,所以interfaces_count=0,這時(shí)候也就沒有interfaces[]了。

fields_count和fields[]

然后是字段數(shù)目和字段具體的數(shù)組信息。

這里的字段包括類變量和實(shí)例變量。

每個(gè)字段信息也是一個(gè)結(jié)構(gòu)體:

field_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

字段的access_flag跟class的有點(diǎn)不一樣:

這里我們就不具體對(duì)比解釋了,感興趣的小伙伴可以自行體驗(yàn)。

methods_count和methods[]

接下來是方法信息。

method結(jié)構(gòu)體:

method_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

method訪問權(quán)限標(biāo)記:

attributes_count和attributes[]

attributes被用在ClassFile, field_info, method_info和Code_attribute這些結(jié)構(gòu)體中。

先看下attributes結(jié)構(gòu)體的定義:

attribute_info {
    u2 attribute_name_index;
    u4 attribute_length;
    u1 info[attribute_length];
}

都有哪些attributes, 這些attributes都用在什么地方呢?

其中有六個(gè)屬性對(duì)于Java虛擬機(jī)正確解釋類文件至關(guān)重要,他們是:
ConstantValue,Code,StackMapTable,BootstrapMethods,NestHost和NestMembers。

九個(gè)屬性對(duì)于Java虛擬機(jī)正確解釋類文件不是至關(guān)重要的,但是對(duì)于通過Java SE Platform的類庫正確解釋類文件是至關(guān)重要的,他們是:

Exceptions,InnerClasses,EnclosingMethod,Synthetic,Signature,SourceFile,LineNumberTable,LocalVariableTable,LocalVariableTypeTable。

其他13個(gè)屬性,不是那么重要,但是包含有關(guān)類文件的元數(shù)據(jù)。

總結(jié)

最后留給大家一個(gè)問題,java class中常量池的大小constant_pool_count是2個(gè)字節(jié),兩個(gè)字節(jié)可以表示2的16次方個(gè)常量。很明顯已經(jīng)夠大了。

以上就是淺談JVM之java class文件的密碼本的詳細(xì)內(nèi)容,更多關(guān)于JVM之java class文件的密碼本的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java中List<對(duì)象>如何根據(jù)對(duì)象的一個(gè)屬性進(jìn)行去重

    java中List<對(duì)象>如何根據(jù)對(duì)象的一個(gè)屬性進(jìn)行去重

    這篇文章主要給大家介紹了關(guān)于java中List<對(duì)象>如何根據(jù)對(duì)象的一個(gè)屬性進(jìn)行去重的相關(guān)資料,在開發(fā)中可能會(huì)遇到很多需要去重的情況,比如Person對(duì)象有name跟age兩個(gè)屬性,需要根據(jù)age進(jìn)行去重,需要的朋友可以參考下
    2023-08-08
  • Spring負(fù)載均衡LoadBalancer使用詳解

    Spring負(fù)載均衡LoadBalancer使用詳解

    這篇文章主要介紹了Spring負(fù)載均衡LoadBalancer使用詳解,Spring Cloud LoadBalancer是Spring Cloud官方自己提供的客戶端負(fù)載均衡器, 用來替代Ribbon,Spring官方提供了兩種客戶端都可以使用loadbalancer,需要的朋友可以參考下
    2023-11-11
  • SpringBoot整合Ip2region獲取IP地址和定位的詳細(xì)過程

    SpringBoot整合Ip2region獲取IP地址和定位的詳細(xì)過程

    ip2region v2.0 - 是一個(gè)離線IP地址定位庫和IP定位數(shù)據(jù)管理框架,10微秒級(jí)別的查詢效率,提供了眾多主流編程語言的 xdb 數(shù)據(jù)生成和查詢客戶端實(shí)現(xiàn) ,這篇文章主要介紹了SpringBoot整合Ip2region獲取IP地址和定位,需要的朋友可以參考下
    2023-06-06
  • SpringBoot創(chuàng)建WebService方法詳解

    SpringBoot創(chuàng)建WebService方法詳解

    這篇文章主要介紹了SpringBoot如何創(chuàng)建WebService,文中有詳細(xì)的實(shí)現(xiàn)步驟以及示例代碼,對(duì)學(xué)習(xí)或工作有一定的幫助,需要的朋友跟著小編一起來學(xué)習(xí)吧
    2023-05-05
  • poi導(dǎo)出word表格的操作講解

    poi導(dǎo)出word表格的操作講解

    這篇文章主要介紹了poi導(dǎo)出word表格的操作講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • 關(guān)于mybatis plus 中的查詢優(yōu)化問題

    關(guān)于mybatis plus 中的查詢優(yōu)化問題

    這篇文章主要介紹了關(guān)于mybatis plus 中的查詢優(yōu)化問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • LinkedBlockingQueue鏈?zhǔn)阶枞?duì)列的使用和原理解析

    LinkedBlockingQueue鏈?zhǔn)阶枞?duì)列的使用和原理解析

    這篇文章主要介紹了LinkedBlockingQueue鏈?zhǔn)阶枞?duì)列的使用和原理解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Eclipse Debug模式的開啟與關(guān)閉問題簡(jiǎn)析

    Eclipse Debug模式的開啟與關(guān)閉問題簡(jiǎn)析

    這篇文章主要介紹了Eclipse Debug模式的開啟與關(guān)閉問題簡(jiǎn)析,同時(shí)向大家介紹了一個(gè)簡(jiǎn)單的debug模式啟動(dòng)不起來的解決方法,希望對(duì)大家有所幫助。
    2017-10-10
  • Spring?Data?JPA關(guān)系映射@OneToOne實(shí)例解析

    Spring?Data?JPA關(guān)系映射@OneToOne實(shí)例解析

    這篇文章主要為大家介紹了Spring?Data?JPA關(guān)系映射@OneToOne實(shí)例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • Java中HashMap集合的6種遍歷方式詳解

    Java中HashMap集合的6種遍歷方式詳解

    這篇文章主要介紹了Java中HashMap集合的6種遍歷方式詳解,HashMap?基于哈希表的?Map?接口實(shí)現(xiàn),是以?key-value?存儲(chǔ)形式存在,即主要用來存放鍵值對(duì),HashMap?的實(shí)現(xiàn)不是同步的,這意味著它不是線程安全的,我們來看一下其遍歷方式,需要的朋友可以參考下
    2023-12-12

最新評(píng)論