文件详解,深入理解Javaclass文件格式

对此领悟JVM和深深理解Java语言,学习并打听class文件的格式都以必供给调控的功课。原因极粗略,JVM不会了然我们写的Java源文件,大家必得把Java源文件编写翻译成class文件,技巧被JVM识别,对于JVM来说,class文件也正是叁个接口,精通了那个接口,能协助我们更加好的知情JVM的作为;另一方面,class文件以另一种方法再度描述了大家在源文件中要抒发的意味,精晓class文件如何重新描述大家编辑的源文件,对于长远驾驭Java语言和语法都以很有助于的。其他,不管是怎么语言,只要能编译成class文件,都能被JVM识别并实践,所以class文件不仅仅是跨平台的基础,也是JVM跨语言的根基,通晓了class文件格式,对于我们上学基于JVM的任何语言会有十分大扶助。


总之,在全体Java能力系统布局中,class文件处于中等的任务,对于通晓整个系统具备承前启后的功用。如图所示:

Understanding bytecode makes you a better programmer

图片 1

前言

用作二个Java开采者,敌手艺的追求而不止停留在会用API,会写基本功用上,要想在本事上有更加高的功力,就须求浓厚到原理层面去认识代码运转的机制。因而,本文从class字节码文件的结构出手,一步步来解剖二进制字节码的中间职业原理,这对深切精通JVM的运转搭飞机制大有益处,同反常候,对于想要使用BCEL来动态改动Class字节码指令的行事也很有扶持(示例:JVM Class字节码之三-使用BCEL更动类属性)。

Class文件格式概述

什么是Class文件

Java字节码类文件(.class)是Java编写翻译器编写翻译Java源文件(.java)爆发的“指标文件”。它是一种8位字节的二进制流文件, 各样数据项按顺序紧凑的过去向后排列, 相邻的项之间从未空闲, 那样能够使得class文件特别紧密, 体积轻便, 可以被JVM快捷的加载至内部存款和储蓄器, 並且吞没比较少的内部存款和储蓄器空间(方便于互连网的传导)。

Java源文件在被Java编写翻译器编写翻译之后, 每一个类(大概接口)都单身攻克贰个class文件, 并且类中的全体音信都会在class文件中有照料的叙说, 由于class文件很灵敏, 它依旧比Java源文件有着更加强的描述本领。

class文件中的音讯是一项一项排列的, 每项数据都有它的稳定长度, 有的占一个字节, 有的占五个字节, 还会有的占多少个字节或8个字节, 数据项的两样长短分别用u1, u2, u4, u8象征, 分别代表一种多少项在class文件中并吞多少个字节, 五个字节, 4个字节和8个字节。 能够把u1, u2, u3, u4看做class文件数量项的“类型” 。

class文件是一种8位字节的二进制流文件,各样数据项按顺序紧密的早年向后排列,相邻的项之间平昔不空闲,那样能够使得class文件极度紧密,体量轻易,能够被JVM急忙的加载至内部存款和储蓄器,何况攻克比较少的内部存款和储蓄器空间。大家的Java源文件,在被编写翻译之后,各种类都单身攻下一个class文件,并且类中的全数音信都会在class文件中有照顾的叙述,由于class文件很利索,它竟然比Java源文件有着更加强的陈述手艺。

Class文件的结构

一个举世无双的class文件分为:MagicNumber,Version,Constant_pool,Access_flag,This_class,Super_class,Interfaces,菲尔德s,Methods 和Attributes那12个部分,用一个数据结构能够表示如下:

图片 2

class_code.PNG-21.1kB

上边前蒙受class文件中的各类进行详细的分解:

1、magic
在class文件发轫的八个字节, 寄存着class文件的魔数, 那个魔数是class文件的注解,他是一个稳固的值: 0XCAFEBABE 。 也便是说他是判别二个文件是或不是class格式的公文的规范, 若是开端多个字节不是0XCAFEBABE, 那么就证实它不是class文件, 不能够被JVM识别。

2、minor_version 和 major_version
随后魔数的八个字节是class文件的此版本号和主版本号。
随着Java的开采进取, class文件的格式也会做相应的改换。 版本号标识着class文件在如曾几何时候, 到场或改动了怎么着特征。 譬世尊讲, 差别版本的javac编写翻译器编写翻译的class文件, 版本号大概区别, 而分歧版本的JVM能辨别的class文件的版本号也或然差异, 常常情况下, 高版本的JVM能识别低版本的javac编写翻译器编写翻译的class文件, 而低版本的JVM不能够鉴定区别高版本的javac编译器编写翻译的class文件。 假使运用低版本的JVM施行高版本的class文件, JVM会抛出java.lang.UnsupportedClassVersionError 。具体的本子号变迁这里不再商量, 供给的读者自行查阅资料。

3、constant_pool
在class文件中, 位于版本号前边的正是常量池相关的数额项。 常量池是class文件中的一项十三分首要的多少。 常量池中存放了文字字符串, 常量值, 当前类的类名, 字段名, 方法名, 各种字段和办法的描述符, 对当前类的字段和章程的引用新闻, 当前类中对其他类的引用音信等等。 常量池中大约饱含类中的全数音信的描述, class文件中的比非常多任何部分都以对常量池中的数据项的引用,举例后边要讲到的this_class, super_class, field_info, attribute_info等, 另外字节码指令中也存在对常量池的引用, 这些对常量池的引用充当字节码指令的四个操作数。别的,常量池中相继项也会互相援用。

常量池是贰个类的布局索引,别的地点对“对象”的援用能够通过索引地点来代替,大家领略在程序中八个变量能够穿梭地被调用,要高效获得这么些变量常用的点子正是通过索引变量。这种索引咱们得以直观通晓为“内部存款和储蓄器地址的虚拟”。大家把它叫静态池的意味正是说这里维护着通过编写翻译“梳理”之后的对峙固化的数量索引,它是站在全体JVM(进度)层面包车型大巴共享池。

class文件中的项constant_pool_count的值为1, 表达每一种类都唯有一个常量池。 常量池中的数据也是一项一项的, 未有空闲的次第排泄。常量池中逐条数据项通过索引来访谈, 有一点类似与数组, 只不过常量池中的第一项的目录为1, 而不为0, 如若class文件中的其余地点引用了索引为0的常量池项, 就表明它不引用任何常量池项。class文件中的各种多少项都有本人的类型, 同样的道理,常量池中的各样多少项也是有谈得来的项目。 常量池中的数据项的项目如下表:

图片 3

constant_pool.PNG-25.4kB

每一个数据项叫做三个XXX_info项,比方,贰个常量池中四个CONSTANT_Utf8类型的项,正是贰个CONSTANT_Utf8_info 。除外, 每一种info项中都有三个标识值(tag),那么些标识值声明了这几个常量池中的info项的品类是怎么着, 从上边的表格中能够见到,四个CONSTANT_Utf8_info中的tag值为1,而一个CONSTANT_Fieldref_info中的tag值为9 。

Java程序是动态链接的, 在动态链接的兑现中, 常量池扮演者尤为重要的剧中人物。 除了贮存一些字面量之外, 常量池中还存放着以下两种标识引用:
(1) 类和接口的全限定名
(2) 字段的名称和描述符
(3) 方法的称号和陈诉符
我们有必不可缺先领会一下class文件中的特殊字符串, 因为在常量池中, 特殊字符串大量的出现,那一个非常字符串就是上边说的全限定名和描述符。对于常量池中的特殊字符串的刺探,能够参考此文书档案:Java class文件格式之特殊字符串_引力节点Java高校整理

4、access_flag 保存了现阶段类的拜访权限

5、this_cass 保存了当前类的全局限定名在常量池里的目录

6、super class 保存了现阶段类的父类的全局限定名在常量池里的目录

7、interfaces 保存了当下类完毕的接口列表,包蕴两有些内容:interfaces_count 和interfaces[interfaces_count]
interfaces_count 指的是现阶段类完毕的接口数目
interfaces[] 是包含interfaces_count个接口的全局限定名的目录的数组

8、fields 保存了这段日子类的分子列表,包罗两有的的开始和结果:田野同志s_count 和 fields[fields_count]
fields_count是类变量和实例变量的字段的多少总和。
fileds[]是富含字段详细新闻的列表。

9、methods 保存了现阶段类的章程列表,包括两有的的内容:methods_count和methods[methods_count]
methods_count是此类只怕接口展现定义的不二等秘书籍的数量。
method[]是含有方法消息的贰个详细列表。

10、attributes 包括了当下类的attributes列表,满含两有的内容:attributes_count 和 attributes[attributes_count]
class文件的最后一部分是性质,它汇报了此类大概接口所定义的一些品质音讯。attributes_count指的是attributes列表中含有的attribute_info的数量。
属性能够出现在class文件的重重地方,而不只是出新在attributes列表里。如若是attributes表里的习性,那么它正是对总体class文件所对应的类依然接口的陈诉;如果出现在fileds的某一项里,那么它就是对该字段额外信息的描述;若是现身在methods的某一项里,那么它便是对该方法额外音信的陈述。

class文件中的音讯是一项一项排列的,每项数据皆有它的平素长度,有的占贰个字节,有的占五个字节,还会有的占七个字节或8个字节,数据项的不等长短分别用u1,u2,u4,u8意味,分别代表一种多少项在class文件中据有八个字节,八个字节,4个字节和8个字节。能够把u1,u2,u3,u4看做class文件数量项的“类型”。

透过演示代码来手动深入分析class文件

地点大致讲明了弹指间class文件的组织,这里,大家拿二个class文件做三个简短的剖析,来证实方面包车型大巴文书结构是还是不是真正是如此。

咱俩在此处新建多个java文件,Hello.java,具体内容如下:

    public class Hello{
      private int test;
      public int test(){
            return test;
        }
    }

下一场再经过javac命令将此java文件编写翻译成class文件:

javac /d/class_file_test/Hello.java

编写翻译之后的class文件十六进制结果如下所示,能够用UltraEdit等十六进制编辑器打开,获得:

图片 4

hello_class_test.PNG-22.6kB

接下去大家就依据class文件的格式来解析上边的一串数字,依然遵守事先的各样来:

  1. magic:
    CA FE BA BE ,代表该公文是叁个字节码文件,大家通常分别文件类型都以经过后缀名来不一致的,不未来缀名是能够不管修改的,所以仅靠后缀名不能够真正区分三个文本的品类。区分文件类型的另个点子正是magic数字,JVM 正是经过 CA FE BA BE 来判别该公文是还是不是class文件

  2. version字段
    00 00 00 34,前五个字节00是minor_version,后多个字节0034是major_version字段,对应的十进制值为52,也正是说当前class文件的主版本号为52,次版本号为0。下表是jdk 1.6 现在对应帮忙的 Class 文件版本号:

    图片 5 image_1c2th3nii1otd13vg1vhg1hl6itg4i.png-23.7kB

  3. 常量池,constant_pool:
    3.1. constant_pool_count
    随即version字段下来的几个字节是:00 12意味着常量池里带有的常量数目,因为字节码的常量池是从1从头计数的,那么些常量池包涵十四个(0x0012-1)常量。

3.2.**constant_pool**  
接下来就是分析这17个常量:

3.2.1. 首先个变量 0a 00 04 00 0e
首先,紧接着constant_pool_count的第二个字节0a(tag=10)依据下面的表格(文中第二张图纸)

  ![image_1c2tj6ib6pslkbb1876ot81rjj4v.png-4kB][7]

可知,这表示的是一个CONSTANT_Methodref。CONSTANT_Methodref的结构如下:

               CONSTANT_Methodref_info {
                         u1 tag;    //u1表示占一个字节
                         u2 class_index;    //u2表示占两个字节
                         u2 name_and_type_index;    //u2表示占两个字节
               }

其中class_index表示该方法所属的类在常量池里的目录,name_and_type_index表示该措施的称呼和品种的目录。常量池里的变量的目录从1早先。

那么那几个methodref结构的多少如下:

                    0a  //tag  10表示这是一个CONSTANT_Methodref_info结构
                    00 04 //class_index 指向常量池中第4个常量所表示的类
                    00 0e  //name_and_type_index 指向常量池中第14个常量所表示的方法

3.2.2. 次之个变量09 00 03 00 0F
进而是第二个常量,它的tag是09,根据地方的报表可见,那意味的是贰个CONSTANT_Fieldref的结构,它的构造如下:

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

和地点的变量基本一致。

                        09 //tag
                        00 03 //指向常量池中第3个常量所表示的类
                        00 0f //指向常量池中第15个常量所表示的变量

3.2.3. 第多个变量 07 00 10
tag为07表示是叁个CONSTANT_Class变量,那么些变量的组织如下:

                CONSTANT_Class_info {
                         u1 tag;
                         u2 name_index;
               }

除此之外tag字段以外,还应该有贰个name_index的值为00 10,就是指向常量池中第十七个常量所代表的Class名称。

3.2.4. 第四个变量07 00 11
同上,也是贰个CONSTANT_Class变量,可是,指向的是第拾五个常量所代表的Class名称。

3.2.5. 第多少个变量 01 00 04 74 65 73 74
tag为1,表示那是一个CONSTANT_Utf8组织,这种布局用UTF-8的一种变体来代表字符串,结构如下所示:

                    CONSTANT_Utf8_info {
                                   u1 tag;
                                   u2 length;
                                   u1 bytes[length];
                    }

里面length表示该字符串的字节数,bytes字段富含该字符串的二进制表示。

                        01 //tag  1表示这是一个CONSTANT_Utf8结构
                        00 04 //表示这个字符串的长度是4字节,也就是后面的四个字节74 65 73 74
                        74 65 73 74 //通过ASCII码表转换后,表示的是字符串“test”

接下去的8个变量都以字符串,这里就不具体深入分析了。

3.2.6. 第21个常量 0c 00 07 00 08
tag为0c,表示那是多个CONSTANT_NameAndType结构,这么些布局用来汇报叁个方法也许成员变量。具体组织如下:

                    CONSTANT_NameAndType_info {
                              u1 tag;
                              u2 name_index;
                              u2 descriptor_index;
                    }

name_index表示的是该变量大概措施的称呼,这里的值是0007,表示针对第7个常量,便是<init>

descriptor_index指向该措施的描述符的援用,这里的值是0008,表示针对第8个常量,正是()V,由前边描述符的语法可知,那么些格局是贰个无参的,再次回到值为void的点子。

综上所述多个字段,能够推出那几个点子是void <init>()。也便是指向那一个NameAndType结构的Methodref的不二等秘书籍名字为void <init>(),约等于说第贰个常量表示的是void <init>()办法,那一个点子其实正是此类的暗许构造方法。

3.2.7. 第二十一个常量也是三个CONSTANT_NameAndType,表示的格局名称叫“int test()”,第4个常量引用了那么些NameAndType,所以第三个常量表示的是“int test()”方法。

3.2.8. 第16和14个常量也是字符串,能够遵守前边的秘籍剖析。

3.3. 完整的常量池
最终,通过上述分析,完整的常量池如下:

          00 12  常量池的数目 18-1=17
          0a 00 04 00 0e  方法:java.lang.Ojbect void <init>()
          09 00 03 00 0f   方法 :Hello int test() 
          07 00 10  字符串:Hello
          07 00 11 字符串:java.lang.Ojbect
          01 00 04 74 65 73 74 字符串:test
          01 00 01 49  字符串:I
          01 00 06 3c 69 6e 69 74 3e 字符串:<init>
          01 00 03 28 29 56 字符串:()V
          01 00 04 43 6f 64 65 字符串:Code 
          01 00 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 字符串:LineNumberTable 
          01 00 03 28 29 49 字符串:()I
          01 00 0a 53 6f 75 72 63 65 46 69 6c 65 字符串:SourceFile
          01 00 0a 48 65 6c 6c 6f 2e 6a 61 76 61 字符串:Hello.java
          0c 00 07 00 08 NameAndType:<init> ()V
          0c 00 05 00 06 NameAndType:test I
          01 00 05 48 65 6c 6c 6f 字符串:Hello
          01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 字符串: java/lang/Object

经过那样分析其实特其他累,大家只是为了掌握class文件的原理才来一步一步深入分析每三个二进制字节码。JDK提供了现有的工具得以直接解析此二进制文件,即javap工具(在JDK的bin目录下),大家通过javap命令来深入分析此class文件:

javap -v -p -s -sysinfo -constants /d/class_file_test/Hello.class

分析拿到的结果为:

图片 6

class_file_2.PNG-44.1kB

关于此表各个的详细深入分析,能够参见海外的这一篇文书档案:JVM Internals
关于此表中Method操作指令aload_1,getfield,ireturn的职能,能够参见云溪社区的那篇小说:
JVM Class详解之二 Method字节码指令

发觉了未曾,下不熟悉成代码中的Constant pool跟我们地点解析出来的完整常量池一模二样,有木有!有木有?
那注明大家地点的分析的形成科学!

因此,我们总算弄懂了Constant pool的内幕。

接下去继续看别的的字段。

  1. access_flag(u2)
    00 21那多个字节的数据表示那些变量的拜见标识位,JVM对寻访标记符的正规如下:

图片 7

access_flag.PNG-26.8kB

其一表里面无法直接询问到0021以此值,原因是0021=0020+0001,也正是象征近来class的access_flag是ACC_PUBLIC|ACC_SUPER。ACC_PUBLIC和代码里的public 关键字相对应。ACC_SUPE陆风X8表示当用invokespecial指令来调用父类的方法时索要新鲜处理。

  1. this_class(u2) 00 03
    this_class指向constant pool的索引值,该值必需是CONSTANT_Class_info类型,这里是3,即针对常量池中的第三项,即是“Hello”。

  2. super_class 00 04
    super_class存的是父类的名号在常量池里的目录,这里针对第多个常量,正是“java/lang/Object”。

  3. interfaces
    interfaces包含interfaces_count和interfaces[]七个字段。因为这里未有兑现接口,所以就不设有interfces选项,所以这里的interfaces_count为0(0000),所从前边的源委也对应该为空。

  4. fields

               00 01 fields count        //表示成员变量的个数,此处为1个
               00 02 00 05 00 06 00 00   //成员变量的结构

每种成员变量对应三个田野先生_info结构:

               field_info {
                         u2 access_flags; 0002
                         u2 name_index; 0005
                         u2 descriptor_index; 0006
                         u2 attributes_count; 0000
                         attribute_info attributes[attributes_count];
               }

access_flags为0002,即是ACC_PRIVATE
name_index指向常量池的第四个常量,为“test”
descriptor_index指向常量池的第6个常量为“I”
八个字段结合起来,表达那么些变量是"private int test"。
接下去的是attribute字段,用来描述该变量的品质,因为那个变量未有增大属性,所以attributes_count为0,attribute_info为空。

  1. methods
    00 02 00 01 00 07 00 08 00 01 00 09 ...
    最后边的2个字节是method_count
    method_count:00 02,为何会有多少个措施吗?咱们肯定只写了三个艺术,那是因为JVM 会自动生成三个<init>办法,那一个是类的暗中认可构造方法。

接下去的剧情是五个method_info结构:

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

前多少个字段和田野_info同样,能够深入分析出第贰个方法是“public void <init>()”

                         00 01 ACC_PUBLIC
                         00 07  <init>
                         00 08  V()

接下去是attribute字段,也便是那几个艺术的叠合属性,这里的attributes_count =1,约等于有八个属性。
各类属性的都是二个attribute_info结构,如下所示:

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

JVM预约义了有的attribute,可是编写翻译器自个儿也能够达成团结的attribute写入class文件里,供运转时接纳。分裂的attribute通过attribute_name_index来分歧。JVM规范里对以下attribute进行了预约义:

图片 8

21718047_1346754834pJjH.png-65.4kB

这里的attribute_name_index值为0009,表示针对第9个常量,就是Code。Code Attribute的作用是保存该方法的结构如所对应的字节码,具体的构造如下所示:

     Code_attribute {
          u2 attribute_name_index;
          u4 attribute_length;
          u2 max_stack;
          u2 max_locals;
          u4 code_length;
          u1 code[code_length];
          u2 exception_table_length;
          { 
               u2 start_pc;
               u2 end_pc;
               u2 handler_pc;
               u2 catch_type;
          } exception_table[exception_table_length];
          u2 attributes_count;
          attribute_info attributes[attributes_count];
     }

attribute_length表示attribute所包蕴的字节数,这里为0000001d,正是三二十个字节,不含有attribute_name_index和attribute_length字段。
max_stack表示那一个措施运营的任曾几何时刻所能到达的操作数栈的最大深度,这里是0001
max_locals代表方法试行时期创设的有的变量的多寡,蕴涵用来代表传入的参数的局地变量,这里是0001.
接下去的code_length表示该方法的所满含的字节码的字节数以及现实的指令码。
此地的字节码长度为00000005,便是前面的5个字节 2a b7 00 01 b1为相应的字节码指令的指令码。
参照他事他说加以考察下表能够将方面包车型大巴指令码翻译成对应的助记符:

               2a   aload_0    
               b7   invokespecial
               00   nop
               01   aconst_null
               b1   return

那便是该方法被调用时,设想机所实践的字节码

接下去是exception_table,这里存放的是处理特别的音信。
每个exception_table表项由start_pc,end_pc,handler_pc,catch_type组成。start_pc和end_pc表示在code数组中的从start_pc到end_pc处(包含start_pc,不包含end_pc)的吩咐抛出的可怜会由这几个表项来管理;handler_pc表示管理特其他代码的起来处。catch_type代表会被管理的不胜类型,它指向常量池里的八个特别类。当catch_type为0时,表示管理全数的那多少个,那几个能够用来贯彻finally的作用。

唯独,这段代码里不曾万分处理,所以exception_table_length为0000,所以大家不做剖析。

接下去是该格局的叠合属性,attributes_count为0001,表示有三个叠合属性。
attribute_name_index为000a,指向第十二个常量,为LineNumberTable。那特特性用来代表code数组中的字节码和java代码行数之间的涉及。那些性子能够用来在调解的时候一定代码实践的行数。LineNumberTable的构造如下:

     LineNumberTable_attribute {
               u2 attribute_name_index;
               u4 attribute_length;
               u2 line_number_table_length;
               { u2 start_pc;
               u2 line_number;
          } line_number_table[line_number_table_length];
     }

前方七个字段分别代表那么些attribute的称呼是LineNumberTable以及长度为00000006。接下来的0001象征line_number_table_length,表示line_number_table有贰个表项,个中start_pc为 00 00,line_number为 00 00,表示第0行代码从code的第0个指令码伊始。

末端的剧情是第贰个主意,具体就不再深入分析了。

  1. attributes
    聊起底剩余的从头到尾的经过是attributes,这里的attributes表示一切class文件的附加属性,可是结构依然和前边的attribute保持一致。00 01代表有一个attribute。
    Attribute结构如下:
          SourceFile_attribute {
               u2 attribute_name_index;
               u4 attribute_length;
               u2 sourcefile_index;
          }

attribute_name_index为000c,指向第拾个常量,为SourceFile,说明那脾本性是Source
attribute_length为00000002
sourcefile_index为000d,表示针对常量池里的第十二个常量,为Hello.java
本条本性注解当前的class文件是从Hello.java文件编写翻译而来。

class文件中留存以下数据项(该图片参照他事他说加以考察自《深刻Java设想机》):

字节码修改才能

对Java Class字节码剖判,大家应该力所能致比较清楚的认知到全方位字节码的组织。

那通过打听字节码,大家得以做些什么呢?

其实通过字节码能做过多平常我们不或许做到的劳作。例如,在类加载此前拉长某个操作依旧直接动态的生成字节。

ASM 是四个 Java 字节码操控框架。它亦能够二进制情势修改已有类或许动态生成类。ASM 能够一向发生二进制 class 文件,也能够在类被加载入 Java 设想机在此之前动态退换类表现。ASM 从类文件中读入信息后,能够改换类行为,剖析类新闻,乃至可以基于客户要求扭转新类。不过ASM在创制class字节码的进程中,操纵的品级是底层JVM的汇编指令等级,那须要ASM使用者要对class组织结构和JVM汇编指令有一定的摸底。

当下字节码修改技艺有ASM,javassist,cglib,BCEL等。cglib便是依照封装的Asm. Spring 正是选择cglib代理库。关于cglib的运用介绍,可以参照:CGLIB介绍与原理

Javassist是七个开源的剖释、编辑和创办Java字节码的类库。是由东京(Tokyo)科学和技术大学的数学和管理器科学系的 Shigeru Chiba (千叶 滋)所创建的。它已步入了开放源代码JBoss 应用服务器项目,通过应用Javassist对字节码操作为JBoss完毕动态AOP框架。javassist是jboss的叁个子项目,其首要的优点,在于轻便,并且神速。直接行使java编码的方式,而无需理解设想机指令,就能够动态改动类的组织,或然动态生成类。

图片 9

参考文书档案

  1. Java Code to Byte Code
  2. JVM Internals
  3. 从字节码层面看“HelloWorld”
  4. ASM官网
  5. CGLIB介绍与原理
  6. CGLIB(Code Generation Library)详解
  7. JVM之字节码——Class文件格式
  8. 云溪社区--JVM Class详解之一
  9. 云溪社区--JVM Class字节码之三-使用BCEL改换类属性
  10. 国外翻译小说:Java 编程的动态性,用 BCEL 设计字节码

上面临class文件中的各个进行详细的表明。

class文件中的魔数和本子号

magic

在class文件伊始的多少个字节,贮存着class文件的魔数,这么些魔数是class文件的注解,他是三个稳住的值:0XCAFEBABE。也正是说他是推断三个文书是否class格式的文书的规范,若是初阶七个字节不是0XCAFEBABE,那么就申明它不是class文件,不可能被JVM识别。

minor_version和major_version

随之魔数的多个字节是class文件的此版本号和主版本号。随着Java的发展,class文件的格式也会做相应的更换。版本号标识着class文件在什么日期,插手或转移了什么特征。举个例子来讲,不相同版本的javac编写翻译器编写翻译的class文件,版本号大概两样,而各异版本的JVM能分辨的class文件的版本号也大概两样,日常情况下,高版本的JVM能鉴定区别低版本的javac编写翻译器编写翻译的class文件,而低版本的JVM不能够辨识高版本的javac编译器编写翻译的class文件。假设运用低版本的JVM实施高版本的class文件,JVM会抛出java.lang.UnsupportedClassVersionError。具体的本子号变迁这里不再探讨,须要的读者自行查阅资料。

class文件中的常量池概述

在class文件中,位于版本号后边的正是常量池相关的数额项。常量池是class文件中的一项非常主要的多少。常量池中寄存了文字字符串,常量值,当前类的类名,字段名,方法名,各种字段和措施的描述符,对脚下类的字段和艺术的引用消息,当前类中对任何类的援引新闻等等。常量池中差非常少包括类中的全体音讯的描述,class文件中的比非常多任何部分都以对常量池中的数据项的援引,比方前边要讲到的this_class,super_class,field_info,attribute_info等,别的字节码指令中也存在对常量池的引用,那一个对常量池的援引充任字节码指令的贰个操作数。其它,常量池中相继项也会互相引用。

class文件中的项constant_pool_count的值为1,表达各种类都唯有一个常量池。常量池中的数据也是一项一项的,未有空闲的相继排泄。常量池中相继数据项通过索引来访谈,有一些类似与数组,只但是常量池中的第一项的目录为1,而不为0,假若class文件中的别的地方引用了索引为0的常量池项,就评释它不援用任何常量池项。class文件中的各类多少项都有友好的品种,同样的道理,常量池中的每一类多少项也是有和好的档案的次序。常量池中的数据项的档期的顺序如下表:

图片 10

各种数据项叫做一个XXX_info项,比如,叁个常量池中二个CONSTANT_Utf8类型的项,正是二个CONSTANT_Utf8_info。除却,每种info项中都有叁个标记值,这么些标识值注脚了那几个常量池中的info项的门类是什么,从上边的表格中能够看看,一个CONSTANT_Utf8_info中的tag值为1,而一个CONSTANT_Fieldref_info中的tag值为9。

Java程序是动态链接的,在动态链接的落实中,常量池扮演者十分重要的剧中人物。除了存放一些字面量之外,常量池中还贮存着以下二种标记援引:

类和接口的全限定名

主意的名号和呈报符

在详细疏解常量池中的各种数据项此前,大家有供给先精通一下class文件中的特殊字符串,因为在常量池中,特殊字符串大量的产出,这一个新鲜字符串正是上边说的全限定名和描述符。要驾驭常量池中的各样数据项,必得先掌握这个极度字符串。

本文由365bet体育在线官网发布于网络编程,转载请注明出处:文件详解,深入理解Javaclass文件格式

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。