实例分析Java Class的文件结构,实例分析java

图片 68

Java
Class文本中包罗以下音信:

实例剖析Java Class的文书结构,实例解析java

学学Java的恋人应该都清楚Java从刚伊始的时候就打着平台无关性的暗记,说“一回编写,四处运转”,其实聊到无关性,Java平台还恐怕有此外多个非亲非故性那正是言语无关性,要落到实处语言非亲非故性,那么Java体系中的class的文书构造仍旧说是字节码就显得优质关键了,其实Java从刚开首的时候就有两套
标准,三个是Java语言职业,其它八个是Java虚构机规范,Java语言专门的学问只是规定了Java语言相关的自律以致法则,而设想机规范则才是确实从跨
平台的角度去规划的。前几日大家就以八个实际的例子来探视,到底Java中三个Class文件对应的字节码应该是如何体统。
那篇作品将率先总体上论述一下Class到底由哪些内容结合,然后再用叁个其实的Java类入手去深入分析class的文本布局。

在持续此前,大家率先供给鲜明如下几点:

1)Class文件是有8个字节为基础的字节流构成的,这几个字节流之间都严厉依照规定的顺序排列,况且字节之间不设有别的空隙,对于当先8个字节的多寡,将依照Big-Endian的顺序存储的,也便是说高位字节存款和储蓄在低的地点上边,而未有字节存款和储蓄到高地址上边,其实那也是class文件要跨平台的要害,因为
PowerPC构造的拍卖利用Big-Endian的蕴藏顺序,而x86种类的计算机则应用Little-Endian的存放顺序,因而为了Class文
件在各中微机布局下保持统一的仓库储存顺序,设想机规范必须对起张开联合。

2)
Class文件构造接纳相像C语言的构造体来囤积数据的,首要有两类数据项,无符号数和表,无符号数用来表述数字,索引援用以至字符串等,比方u1,u2,u4,u8独家表示1个字节,2个字节,4个字节,8个字节的无符号数,而表是有四个无符号数以至此外的表组成的复合结构。也许咱们看看这里
对无标记数和表到底是地方亦不是很精晓,不过没什么,等下部实例的时候,作者会再以实例来降解。

明明了上边的两点未来,大家接下去后来寻访Class文件中遵守严俊的顺序排列的字节流都切实富含些什么数据:

图片 1

(上海图书馆来自The Java Virtual Machine Specification Java SE 7 艾德ition卡塔尔

在看上海体育场合的时候,有点大家需求小心,比方cp_info,cp_info代表常量池,上海教室中用
constant_pool[constant_pool_count-1]的不二诀要来表示常量池有constant_pool_count-1个常量,它
这里是利用数组的表现情势,可是大家不用误感觉全数的常量池的常量长度都以同一的,其实那个地点只是为了有助于描述接受了数组的主意,不过此间并不像编制程序语
言这里,一个int型的数组,每种int长度都同一。明显了那或多或少之后,大家在回过头来看看上海教室中每一项都具体代表了怎么样含义。

1)u4 magic
表示魔数,况且魔数占用了4个字节,魔数到底是做什么样的啊?它实质上正是象征一下以此文件的品类是叁个Class文件,并不是一张JPG图片,或许AVI的电影。而Class文件对应的魔数是0xCAFEBABE.

2)u2 minor_version
代表Class文件的次版本号,何况此版本号是u2类型的无符号数表示。

3) u2 major_version
表示Class文件的主版本号,並且主版本号是u2品类的无符号数表示。major_version和minor_version首要用来代表如今的虚构机是不是选择当前这种本子的Class文件。差异版本的Java编译器编写翻译的Class文件对应的版本是不一样的。高版本的设想机援助低版本的编写翻译器编写翻译的
Class文件布局。举例Java SE 6.0对应的设想机帮衬Java SE
5.0的编写翻译器编写翻译的Class文件布局,反之则极度。

4) u2 constant_pool_count
代表常量池的多少。这里大家供给珍视来说一下常量池是何等东西,请我们不用与Jvm内存模型中的运营时常量池混淆了,Class文件中常量池首要囤积了字
面量以致符号援引,个中字面量首要回顾字符串,final常量的值或许有个别属性的开头值等等,而符号援引重要存储类和接口的全节制称号,字段的称号以致描
述符,方法的称呼以至描述符,这里名称恐怕我们都轻松通晓,至于描述符的定义,放到上边说字段表以至艺术表的时候再说。别的大家都了然Jvm的内部存款和储蓄器模型中
有堆,栈,方法区,程序计数器构成,而方法区中又存在一块区域叫运维时常量池,运营时常量池中寄存的东西其实也等于编写翻译器长生的各类字面量以致符号引用,
只可是运营时常量池具有动态性,它能够在运作的时候向里面扩大此外的常量进去,最具代表性的正是String的intern方法。

5)cp_info
表示常量池,这里面就存在了地点说的多如牛毛的字面量和标志征引。放到常量池的中数据项在The
Java Virtual Machine Specification Java SE 7 Edition
中计算有16个常量,种种常量都以二个表,况兼各样常量都用一个集体的部分tag来表示是哪个种类档次的常量。

下边分别轻易描述一下切实细节等到前面的实例 中我们再细化。

CONSTANT_Utf8_info tag标识位为1,
UTF-8编码的字符串CONSTANT_Integer_info tag标记位为3,
整形字面量CONSTANT_Float_info tag标识位为4,
浮点型字面量CONSTANT_Long_info tag标记位为5,
长整形字面量CONSTANT_Double_info tag标记位为6,
双精度字面量CONSTANT_Class_info tag标记位为7,
类或接口的符号引用CONSTANT_String_info
tag标记位为8,字符串类型的字面量CONSTANT_Fieldref_info tag标识位为9,
字段的号子援用CONSTANT_Methodref_info
tag标识位为10,类中艺术的旗号援引CONSTANT_InterfaceMethodref_info
tag标记位为11, 接口中方法的标记援引CONSTANT_NameAndType_info tag
标识位为12,字段和方法的名称甚至项指标标志援引

6) u2 access_flags 表示类可能接口的访谈新闻,具体如下图所示:
图片 2

7)u2 this_class
代表类的常量池索引,指向常量池中CONSTANT_Class_info的常量

8)u2 super_class
表示超类的目录,指向常量池中CONSTANT_Class_info的常量

9)u2 interface_counts 表示接口的数码

10)u2
interface[interface_counts]表示接口表,它里面每一类都针对常量池中CONSTANT_Class_info常量

11)u2 fields_count 表示类的实例变量和类变量的数目

12) field_info
fields[fields_count]代表字段表的消息,个中字段表的协会如下图所示:

图片 3

上图中access_flags表示字段的走访表示,比方字段是public,private,protect
等,name_index表示字段名
称,指向常量池中项目是CONSTANT_UTF8_info的常量,descriptor_index表示字段的描述符,它也本着常量池中项目为
CONSTANT_UTF8_info的常量,attributes_count表示字段表中的属性表的数据,而属性表是则是一种用与叙述字段,方法以至类的天性的可扩展的布局,不一致版本的Java虚构机所支撑的属性表的数额是不一样的。

13) u2 methods_count表示方法表的数据

14)method_info 表示方法表,方法表的实际组织如下图所示:

图片 4
其中access_flags表示方法的探问表示,name_index表示名称的目录,descriptor_index表示方法的叙说
符,attributes_count以及attribute_info相像字段表中的属性表,只不过字段表和议程表中属性表中的属性是分化的,举例方法
表中就Code属性,表示方法的代码,而字段表中就从未有过Code属性。当中具体Class中到底有稍微种属性,等到Class文件构造中的属性表的时候再
说说。

15)
attribute_count表示属性表的多少,聊到属性表,我们须求显著以下几点:

属性表存在于Class文件布局的最后,字段表,方法表以致Code属性中,约等于说属性表中也可以存在属性表属性表的尺寸是不牢固的,不一样的习性,属性表的长短是例外的

上边讲完了Class文件布局中每一种的组合未来,大家以三个实际上的例证来评释以下方面所说的内容。
复制代码 代码如下:
package com.ejushang.TestClass;
public class TestClass implements Super{
private static final int staticVar = 0;
private int instanceVar=0;
public int instanceMethod(int param){
return param+1;
}
}
interface Super{ }

通过jdk1.6.0_37的javac
编写翻译后的TestClass.java对应的TestClass.class的二进制布局如下图所示:

图片 5

上面大家就依据后面所说的Class的文书构造来解析以下上海教室中字节流。

1)魔数
从Class的文本布局大家通晓,刚初始的4个字节是魔数,上海体育场面中从地址00000000h-00000003h的原委便是魔数,从上海体育场合可见Class的文书的魔数是0xCAFEBABE。

2)主次版本号
接下去的4个字节是前后相继版本号,有上海教室可以从00000004h-00000005h对应的是0×0000,由此Class的minor_version
为0×0000,从00000006h-00000007h对应的开始和结果为0×0032,因而Class文件的major_version版本为
0×0032,那适逢其会就是jdk1.6.0不带target参数编写翻译后的Class对应的次第版本。

3)常量池的数目
接下去的2个字节从00000008h-00000009h表示常量池的多寡,由上海体育地方能够知晓其值为0×0018,十进制为22个,可是对于常量池的数量
供给分明一点,常量池的数目是constant_pool_count-1,为何减一,是因为索引0代表class中的数据项不引用任何常量池中的常
量。

4)常量池
我们地点说了常量池中有两样本种的常量,上边就来探视TestClass.class的第多少个常量,大家领略种种常量都有贰个u1连串的tag标志来代表
常量的花色,上海体育场地中0000000ah处的剧情为0x0A,转变来二级制是10,有上面的关于常量类型的描述可以预知tag为10的常量是Constant_Methodref_info,而Constant_Methodref_info的结够如下图所示:

图片 6

其中class_index指向常量池中项目为CONSTANT_Class_info的常量,从TestClass的二进制文件构造中得以观看class_index的值为0×0004(地址为0000000bh-0000000chState of Qatar,也正是说指向第几个常量。

name_and_type_index指向常量池中项目为CONSTANT_NameAndType_info常量。从上海体育场面能够看出name_and_type_index的值为0×0013,表示针对常量池中的第贰11个常量。

接下去又能够透过一致的法子来找到常量池中的所有常量。然则JDK提供了二个方便的工具得以让我们查阅常量池中所满含的常量。通过javap
-verbose TestClass 就可以获得全数常量池中的常量,截图如下:

图片 7

从上海体育场面我们得以知晓的收看,TestClass中常量池有二十多个常量,不忘记记了第0个常量,因为第0个常量被用来代表
Class中的数据项不引用任何常量池中的常量。从上面的剖释中大家得悉TestClass的首先个常量表示方法,在那之中class_index指向的第一个常量为java/lang/Object,name_and_type_index指向的第三十叁个常量值为<init>:(State of QatarV,从那边能够观看第一个象征方法的常量表示的是java编写翻译器生成的实例构造器方法。通过相仿的不二等秘书籍能够深入分析常量池的其余常量。OK,分析完常量池,我们接下去再深入分析下access_flags。
5)u2 access_flags
表示类大概接口方面包车型地铁访谈新闻,比方Class表示的是类依旧接口,是还是不是为public,static,final等。具体访问标识的意义从前已经说过
了,上边大家就来会见TestClass的访问标识。Class的访谈标识是从0000010dh-0000010e,期值为0×0021,依据前边说的
种种访谈标识的标识位,大家可以通晓:0×0021=0×0001|0×0020 也即ACC_PUBLIC

ACC_SUPER为真,其中ACC_PUBLIC我们好明白,ACC_SUPE本田UR-V是jdk1.2后头编写翻译的类都会含有的评释。

6)u2 this_class
表示类的索引值,用来表示类的全节制称号,类的索引值如下图所示:

图片 8

从上海教室可知到看见,类索引值为0×0003,对应常量池的第八个常量,通过javap的结果,大家精晓第多少个常量为
CONSTANT_Class_info类型的常量,通过它能够驾驭类的全约束名称叫:com/ejushang/TestClass
/TestClass

7)u2 super_class
表示近年来类的父类的索引值,索引值所指向的常量池中项目为CONSTANT_Class_info的常量,父类的索引值如下图所示,其值为0×0004,
查看常量池的第多个常量,可以知道TestClass的父类的全约束名字为:java/lang/Object

图片 9

8)interfaces_count和
interfaces[interfaces_count]
意味着接口数量以至实际的每叁个接口,TestClass的接口数量以至接口如下图所示,在那之中0×0001象征兵接兵口数量为1,而0×0005象征兵接兵口在常量池的索引值,找到常量池的第三个常量,其项目为CONSTANT_Class_info,其
值为:com/ejushang/TestClass/Super

图片 10

9)fields_count 和 field_info,
fields_count表示类中田野_info表的多少,而田野(field卡塔尔_info表示类的实例变量和类变量,这里必要小心的是
田野先生_info不包蕴从父类世襲过来的字段,田野先生_info的布局如下图所示:
图片 11

其中access_flags表示字段的拜望标识,比如public,private,protected,static,final等,access_flags的取值如下图所示:
图片 12

其中name_index 和
descriptor_index都以常量池的索引值,分别表示字段的称呼和字段的描述符,字段的称谓轻巧领悟,可是字段的陈述符怎么样掌握吧?其实在JVM
标准中,对于字段的陈述符规定如下图所示:

图片 13

里头大家需求关注一下上海体育场所最终一行,它意味着的是对一维数组的描述符,对于String[][]的陈述符将是[[
Ljava/lang/String,而对于int[][]的汇报符为[[I。接下来的attributes_count以及
attribute_info分别代表属性表的数量以致属性表。上边大家依旧以下边包车型大巴TestClass为例,来看看TestClass的字段表吧。

第一大家来看一下字段的数据,TestClass的字段的数据如下图所示:

图片 14

从上海教室中能够看来TestClass有五个字段,查看TestClass的源代码可以看到,确实也唯有三个字段,接下去我们看看第叁个字段,我们了然第贰个字段应为private
int staticVar,它在Class文件中的二进制表示如下图所示:

图片 15
内部0x001A表示访问标识,通过查看access_flags表可知,其为ACC_PRIVATE,ACC_STATIC,ACC_FINAL,接下
来0×0006和0×0007分别代表常量池中第6和第7个常量,通过翻看常量池可以见到,其值分别为:staticVar和I,此中staticVar为字
段名称,而I为字段的描述符,通过上边对描述符的分解,I所描述的是int类型的变量,接下去0×0001代表staticVar这几个字段表中的属性表的
数量,从上海体育场面能够staticVar字段对应的属性表有1个,0×0008意味常量池中的第8个常量,查看常量池可以查出此属性为
ConstantValue属性,而ConstantValue属性的格式如下图所示:
图片 16

其中attribute_name_index表述属性名的常量池索引,本例中为ConstantValue,而ConstantValue的
attribute_length固定长度为2,而constantValue_index表示常量池中的援用,本例中,此中为0×0009,查看第9个
常量能够知晓,它代表叁个品类为CONSTANT_Integer_info的常量,其值为0。

地点讲完了private static final int
staticVar=0,下边大家随后说一下TestClass的private int
instanceVar=0,在本例中对instanceVar的二进制表示如下图所示:

图片 17
其间0×0002意味访问标记为ACC_P大切诺基IVATE,0x000A表示字段的称号,它指向常量池中的第十三个常量,查看常量池可知字段名称为instanceVar,而0×0007代表字段的描述符,它指向常量池中的第7个常量,查看常量池能够清楚第7个常量为I,表示项目为
instanceVar的连串为I,最后0×0000表示属性表的数据为0.

10)methods_count 和 method_info
,其中methods_count表示方法的数额,而method_info代表的方法表,在那之中措施表的构造如下图所示:

图片 18

从上海体育场所能够看出method_info和field_info的组织是很相近的,方法表的access_flag的具有标识位以致取值如下图所示:

图片 19

其中name_index和descriptor_index表示的是格局的名目和描述符,他们分别是指向常量池的目录。这里需求结解释一下方法的描述
符,方法的陈述符的布局为:(参数列表)再次回到值,举个例子public int
instanceMethod(int
param卡塔尔(قطر‎的叙说符为:(I)I,表示带有七个int类型参数且重回值也为int类型的不二等秘书技,接下去正是属性数据以致属性表了,方法表和字段表尽管都有属性数量和属性表,不过他们内部所蕴藏的属性是例外。接下来大家就以TestClass来看一下方法表的二进制表示。首先来看一下办法表数据,截图如下:

图片 20
从上图能够见见方法表的数量为0×0002意味着有多个法子,接下去我们来深入分析第三个办法,大家先是来看一下TestClass的首先个点子的access_flag,name_index,descriptor_index,截图如下:

图片 21
从上航海用体育地方能够理解access_flags为0×0001,从下直面access_flags标识位的陈说,可见艺术的access_flags的取值为
ACC_PUBLIC,name_index为0x000B,查看常量池中的第12个常量,知道方法的称谓为<init>,0x000C表示
descriptor_index表示常量池中的第12常量,其值为(卡塔尔V,表示<init>方法未有参数和返回值,其实这是编写翻译器自动生成
的实例布局器方法。接下来的0×0001象征<init>方法的艺术表有1个天性,属性截图如下:
图片 22
从上海教室能够看出0x000D对应的常量池中的常量为Code,表示的主意的Code属性,所以到此地大家应该驾驭方法的那么些代码是储存在Class文件措施表中的属性表中的Code属性中。接下来大家在条分缕析一下Code属性,Code属性的组织如下图所示:
图片 23

其中attribute_name_index指向常量池中值为Code的常量,attribute_length的尺寸表示Code属性表的尺寸(这里
要求专一的时候长度不满含attribute_name_index和attribute_length的6个字节的长短)。

max_stack代表最大栈深度,设想机在运作时依照那几个值来分配栈帧中操作数的纵深,而max_locals代表了部分变量表的存款和储蓄空间。

max_locals的单位为slot,slot是虚构机为部分变量分配内部存款和储蓄器的小不点儿单元,在运营时,对于不超越叁13位类型的数据类型,比如byte,char,int等占用1个slot,而double和Long这种陆拾二位的数据类型则要求分配2个slot,其余max_locals的值并不是负有片段变量所急需的内部存款和储蓄器数量之和,因为slot是能够援引的,当一些变量超越了它的效用域将来,局地变量所攻陷的slot就能够被圈定。

code_length代表了字节码指令的数目,而code表示的时候字节码指令,从上图可以领略code的品种为u1,叁个u1类其他取值为0×00-0xFF,对应的十进制为0-255,方今设想机标准已经定义了200多条指令。

exception_table_length以及exception_table分别表示办法对应的十一分新闻。

attributes_count和attribute_info分别代表了Code属性中的属性数据和属性表,从这里能够见到Class的文书构造中,属性表是很灵活的,它能够存在于Class文件,方法表,字段表以至Code属性中。

接下去大家后续以地点的例证来解析一下,从地方init方法的Code属性的截图中得以见到,属性表的尺寸为0×00000026,max_stack的
值为0×0002,max_locals的取值为0×0001,code_length的长度为0x0000000A,那么00000149h-
00000152h为字节码,接下来exception_table_length的尺寸为0×0000,而attribute_count的值为
0×0001,00000157h-00000158h的值为0x000E,它代表常量池中属性的称号,查看常量池获悉第拾陆个常量的值为
LineNumberTable,LineNumberTable用于描述java源代码的行号和字节码行号的附和关系,它不是运行时必不可缺的属性,要是通
过-g:none的编写翻译器参数来撤销生成那项音信的话,最大的震慑就是特别发生的时候,仓库中不能够显得出出错的行号,调试的时候也无法根据源代码来设置断
点,接下去大家再看一下LineNumberTable的构造如下图所示:

图片 24

其中attribute_name_index上面已经涉嫌过,表示常量池的目录,attribute_length代表属性长度,而start_pc和
line_number分表表示字节码的行号和源代码的行号。本例中LineNumberTable属性的字节流如下图所示:

图片 25

地点解析完了TestClass的第三个方法,通过一致的方法大家得以深入分析出TestClass的第2个法子,截图如下:

图片 26

其中access_flags为0×0001,name_index为0x000F,descriptor_index为0×0010,通过查阅常量池可以领悟此办法为public int instanceMethod(int
param卡塔尔(قطر‎方法。通过和位置相同的艺术我们能够明白instanceMethod的Code属性为下图所示:

图片 27

谈到底大家来深入分析一下,Class文件的习性,从00000191h-00000199h为Class文件中的属性表,当中0×0011象征属性的称呼,查看常量池能够精通属性名字为SourceFile,大家再来看看SourceFile的布局如下图所示:

图片 28

其中attribute_length为属性的长度,sourcefile_index指向常量池中值为源代码文件名称的常量,在本例中SourceFile属性截图如下:

图片 29
其中attribute_length为0×00000002意味着长度为2个字节,而soucefile_index的值为0×0012,查看常量池的第19个常量能够领略源代码文件的名号为TestClass.java

末段,希望对本领感兴趣的相恋的人多交流。个人天涯论坛:()

Class的文本布局,实例解析java
学习Java的对象应该都知道Java从刚从前的时候就打着阳台无关性的幌子,说“二次编写,到处运…

一、概述

其余多个Class文件都对应独一多个类或接口的概念新闻,可是或不是富有的类或接口都得定义在文书中(它们也能够经过类加载器直接扭转卡塔尔。

Class文件是一组以8位字节为底工单位的二进制流,各类数据项严峻按顺序排列,未有其余分隔符。Class文件格式采纳一体系似于C语言结构体的伪构造来积攒数据,这种伪构造唯有二种数据类型:无符号数和表。

无符号数:是大旨数据类型,以u1、u2、u4、u8独家表示1个字节、2个字节、4个字节、8个字节的无符号数,能够用来陈述数字、索引援用、数量值可能遵照UTF-8编码构成的字符串值。

:由多少个无符号数大概此外表作为数据项构成的复合数据类型,全体表都习贯性地以“_info”结尾。整个Class文件精气神儿上就是一张表,如下所示:

类型

名称

数量

u4

magic

1

u2

minor_version

1

u2

major_version

1

u2

constant_pool_count

1

cp_info

constant_pool

constant_pool_count-1

u2

access_flags

1

u2

this_class

1

u2

super_class

1

u2

interfaces_count

1

u2

interfaces

interfaces_count

u2

fields_count

1

field_info

fields

fields_count

u2

methods_count

1

method_info

methods

methods_count

u2

attributes_count

1

attribute_info

attributes

attributes_count

 

 

接下去分别对表中的依次字段作出表达。

 

 

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];    //属性表

}

二、各种字段详明

 

行使上边包车型地铁类进行表明:

[java] view
plain copy

 

  1. package com.test;  
  2.   
  3. public class Test {  
  4.     private int m;  
  5.       
  6.     public int getM(){  
  7.         return m + 1;  
  8.     }  
  9. }  

编写翻译后的class文件如下:

 

图片 30

 

1. 透超过实际例来看

public interface InterA {

    void interA();
} 
public interface InterB {
    String interB(int i);
}
public interface InterC {
    void interC();
}
public class Base implements InterA {

    private int baseInt;
    protected String baseString;

    public int getBaseInt() {
        return baseInt;
    }
    public void setBaseInt(int baseInt) {
        this.baseInt = baseInt;
    }

    @Override
    public void interA() {
        System.out.println("the interA in Base");
    }
} 

 public class Sub extends Base implements InterB, InterC {

    private int subInt;
    private static String subString;
    private static Object subObject;

    public int getSubInt() {
        return subInt;
    }
    public void setSubInt(int subInt) {
        this.subInt = subInt;
    }
    public static String getSubString() {
        return subString;
    }
    public static void setSubString(String subString) {
        Sub.subString = subString;
    }
    public static Object getSubObject() {
        return subObject;
    }
    public static void setSubObject(Object subObject) {
        Sub.subObject = subObject;
    }

    @Override
    public void interC() {
        System.out.println("the interC in Sub");
    }

    @Override
    public String interB(int i) {
        return "the interB in Sub";
    }
}

大家利用WinHex查看Sub类的.class文件:

图片 31

1.魔数

各样class文件的头4个字节称为魔数,它独一的效应是明显那一个文件是不是为三个能被设想机选拔的Class文件。超级多文本存款和储蓄标准中都行使魔数来举办身份辨别,举个例子图片格式gif、jpeg等。使用魔数实际不是进展名来進展识别关键是基于安全地点的思量,因为文件实行格式可以随意纠正。

 

Class文件的魔数为:0xCAFEBABE(咖啡宝物?),这一个魔数仿佛也预示着日后JAVA这么些商标名称的面世。

 

图片 32

 

2. 魔数

成效:显明该公文是或不是是虚构机可选取的class文件。java的魔数统一为
0xCAFEBABE (来源于一款咖啡卡塔尔国。

区域:文件第0~3字节。

2.版本号

第五八个字节是次版本号(Minor Version),第7和第8个字节是主版本号(Major
Version)。

高版本的JDK能够向下宽容从前版本的Class文件,可是爱莫能助运维之后版本的Class文件,即便文件格式并未有爆发变化,设想机也必得屏绝实施抢先其版本号的Class文件。

 

3. 版本号

效能:表示class文件的版本,由minorversion和majorversion组成。

区域:文件第4~7字节。

图片 33

51代表,jdk为1.7.0

内需在意的是java版本号是从45最初的,大版本发表,主版本号+1.高版本的jdk能向下宽容早先版本的class文件,但不相配未来版本的class文件。

3.常量池

图片 34

 

常量池能够掌握为Class文件之中的资源仓库,是Class文件布局中与其他类型事关最多的数据类型,也是占据Class文件空间最大的多寡项目之一,同期也是在Class文件中第一个冒出的表类型数据项目。

是因为常量池中常量的数额是不牢固的故此在常量池输入要求停放叁个2字节长的无符号数constatn_pool_count来表示常量池体积计数值。那么些体量计数从1并非0方始。

 

constant_pool_count:占2字节,0x0016,转变为十进制为22,即表明常量池中有贰拾伍个常量(独有常量池的计数是从1最初的,其余集结类型均从0开始),索引值为1~22。第0项常量具备独刻意义,假如有个别指向常量池索引值的数码在特定情景下须求表达“不援用任何一个常量池项目”的意思,这种气象可以将索引值置为0来代表

 

常量池中首要性存放在两大类常量:字面量和标记援引。字面量如文本字符串、表明为final的常量值等。符号引用包蕴三类常量:类和接口的全约束名、字段的称谓和描述符、方法的称谓和陈述符。

 

常量池中的每一种常量都以一个表,在JDK1.7事情发生前共有11种布局各不一样的表数据组织。这几个表数据构造在表最初的率先位是一个u1连串的标记位,代表当前以此常量归于这种常量类型。如下表所示:

类型

简介

项目

类型

描述

CONSTANT_Utf8_info

utf-8缩略编码字符串

tag

u1

值为1

length

u2

utf-8缩略编码字符串占用字节数

bytes

u1

长度为length的utf-8缩略编码字符串

CONSTANT_Integer_info

整形字面量

tag

u1

值为3

bytes

u4

依据高位在前储存的int值

CONSTANT_Float_info

浮点型字面量

tag

u1

值为4

bytes

u4

安分守己高位在前积累的float值

CONSTANT_Long_info

长整型字面量

tag

u1

值为5

bytes

u8

奉公守法高位在前储存的long值

CONSTANT_Double_info

双精度浮点型字面量

tag

u1

值为6

bytes

u8

信守高位在前积累的double值

CONSTANT_Class_info

类或接口的符号援用

tag

u1

值为7

 

index

u2

针对全约束名常量项的目录

CONSTANT_String_info

字符串类型字面量

tag

u1

值为8

index

u2

指向字符串字面量的目录

CONSTANT_Fieldref_info

字段的标识引用

tag

u1

值为9

index

u2

针对表明字段的类或接口描述符CONSTANT_Class_info的索引项

index

u2

指向字段描述符CONSTANT_NameAndType_info的索引项

CONSTANT_Methodref_info

类中艺术的号子援用

tag

u1

值为10

index

u2

本着注明方法的类描述符CONSTANT_Class_info的索引项

index

u2

针对名称及项目描述符CONSTANT_NameAndType_info的索引项

CONSTANT_InterfaceMethodref_info

接口中方法的标识援引

tag

u1

值为11

index

u2

针对证明方法的接口描述符CONSTANT_Class_info的索引项

index

u2

针对名称及项目描述符CONSTANT_NameAndType_info的索引项

CONSTANT_NameAndType_info

字段或艺术的一对符号引用

tag

u1

值为12

index

u2

指向该字段或措施名称常量项的目录

index

u2

指向该字段或方法描述符常量项的目录

 

先是来看常量池中的第一项常量,其标识位为0x07,是七个CONSTANT_Class_info类型常量,此类型常量代表三个类或接口的标识引用。遵照其数据构造,接下去2位字节用来保存四个索引值,它指向常量池中二个CONSTANT_Utf8_info类型的常量,此常量代表了那一个类或接口的全限制名,索引值为0x0002,即指向了常量池中的第二项常量。

其次项常量标记位为0x01,确实是三个CONSTANT_Utf8_info类型的常量。依照其数据布局,接下去2个字节用来保存utf-8缩略编码字符串长度,其值为0x000D,转变为十进制为13,即接下去的11个字节为八个utf-8缩略编码的字符串,为com/test/Test,能够看出凑巧是测量检验类的全节制名。

 

4. 常量池

常量池的轻重缓急是不牢固的,依照你的类中的常量的多少而定,所以在常量池的输入,放置了一个u2类型的表示常量池中常量个数的常量池体积流速计。计数器从1早前,第0位有独特含义,表示针对常量池的索引值数据不引用其他一个常量池项目。池中的数据项好似数组同样是通过索引访谈的。

图片 35

大家能够精晓的见到,大家常量池中有63-1=陆13个常量。这个常量是什么样吧?

要存放字面量Literal和标识援用Symbolic References。

字面量恐怕是文本字符串,或final的常量值。

标志援引包含以下:

  • 类或接口全约束名 Full Qualified Name
  • 字段名称和描述符 Descriptor
  • 情势名称和叙述符

咱俩应用反编写翻译工具翻看一下:

E:programJVMbincomgisskyclazz>javap -v Sub.class
Classfile /E:/program/JVM/bin/com/gissky/clazz/Sub.class
  Last modified 2015-2-22; size 1363 bytes
  MD5 checksum 2dc77c79e4790422407eb7092085883c
  Compiled from "Sub.java"
public class com.gissky.clazz.Sub extends com.gissky.clazz.Base implements com.gissky.clazz.InterB,com.gissky.clazz.InterC
  SourceFile: "Sub.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             //  com/gissky/clazz/Sub    →类和接口的全限定名    
   #2 = Utf8               com/gissky/clazz/Sub
   #3 = Class              #4             //  com/gissky/clazz/Base
   #4 = Utf8               com/gissky/clazz/Base
   #5 = Class              #6             //  com/gissky/clazz/InterB
   #6 = Utf8               com/gissky/clazz/InterB
   #7 = Class              #8             //  com/gissky/clazz/InterC
   #8 = Utf8               com/gissky/clazz/InterC
   #9 = Utf8               subInt 
  #10 = Utf8              I 
  #11 = Utf8              subString
  #12 = Utf8               Ljava/lang/String;
  #13 = Utf8               subObject
  #14 = Utf8               Ljava/lang/Object;
  #15 = Utf8               <init>
  #16 = Utf8               ()V
  #17 = Utf8               Code
  #18 = Methodref          #3.#19         //  com/gissky/clazz/Base."<init>":()V
  #19 = NameAndType        #15:#16        //  "<init>":()V
  #20 = Utf8               LineNumberTable
  #21 = Utf8               LocalVariableTable
  #22 = Utf8               this
  #23 = Utf8               Lcom/gissky/clazz/Sub;
  #24 = Utf8               getSubInt
  #25 = Utf8               ()I 
  #26 = Fieldref           #1.#27         //  com/gissky/clazz/Sub.subInt:I         → 类中字段的符号引用
  #27 = NameAndType        #9:#10         //  subInt:I                                           → 类中字段的部分符号引用之名称和类型
  #28 = Utf8               setSubInt
  #29 = Utf8               (I)V
  #30 = Utf8               getSubString
  #31 = Utf8               ()Ljava/lang/String;
  #32 = Fieldref           #1.#33         //  com/gissky/clazz/Sub.subString:Ljava/lang/String;
  #33 = NameAndType        #11:#12        //  subString:Ljava/lang/String;
  #34 = Utf8               setSubString
  #35 = Utf8               (Ljava/lang/String;)V
  #36 = Utf8               getSubObject
  #37 = Utf8               ()Ljava/lang/Object;
  #38 = Fieldref           #1.#39         //  com/gissky/clazz/Sub.subObject:Ljava/lang/Object;
  #39 = NameAndType        #13:#14        //  subObject:Ljava/lang/Object;
  #40 = Utf8               setSubObject
  #41 = Utf8               (Ljava/lang/Object;)V
  #42 = Utf8               interC
  #43 = Fieldref           #44.#46        //  java/lang/System.out:Ljava/io/PrintStream;
  #44 = Class              #45            //  java/lang/System
  #45 = Utf8               java/lang/System
  #46 = NameAndType        #47:#48        //  out:Ljava/io/PrintStream;
  #47 = Utf8               out
  #48 = Utf8               Ljava/io/PrintStream;
  #49 = String             #50            //  the interC in Sub
  #50 = Utf8               the interC in Sub
  #51 = Methodref          #52.#54        //  java/io/PrintStream.println:(Ljava/lang/String;)V
  #52 = Class              #53            //  java/io/PrintStream
  #53 = Utf8               java/io/PrintStream
  #54 = NameAndType        #55:#35        //  println:(Ljava/lang/String;)V
  #55 = Utf8               println
  #56 = Utf8               interB
  #57 = Utf8               (I)Ljava/lang/String;
  #58 = String             #59            //  the interB in Sub                                    →方法中用到的String常量
  #59 = Utf8               the interB in Sub
  #60 = Utf8               i
  #61 = Utf8               SourceFile
  #62 = Utf8               Sub.java

常量池中的项目项目如下:

  • CONSTANT_Utf8_info tag标记位为1, UTF-8编码的字符串
  • CONSTANT_Integer_info tag标识位为3, 整形字面量
  • CONSTANT_Float_info tag标记位为4, 浮点型字面量
  • CONSTANT_Long_info tag标记位为5, 长整形字面量
  • CONSTANT_Double_info tag标记位为6, 双精度字面量
  • CONSTANT_Class_info tag标记位为7, 类或接口的号子引用
  • CONSTANT_String_info tag标识位为8,字符串类型的字面量
  • CONSTANT_Fieldref_info tag标识位为9, 字段的标志援用
  • CONSTANT_Methodref_info tag标记位为10,类中艺术的符号引用
  • CONSTANT_InterfaceMethodref_info tag标记位为11,
    接口中方法的标记引用
  • CONSTANT_NameAndType_info tag
    标识位为12,字段和办法的名目以至项指标标识引用

4.访谈标记

 

图片 36

 

在常量池甘休之后,紧接着的多个字节代表做客标记,用于识别部分类还是接口等级次序的访谈音信。如下表所示。

 

志名称

标志值

含义

ACC_PUBLIC

0x0001

是否为public类型

ACC_FINAL

0x0010

是否被声明为final,只有类可设置

ACC_SUPER

0x0020

是否允许使用invokespecial字节码指令,JDK1.2以后编译出来的类这个标志为真

ACC_INTERFACE

0x0200

标识这是一个接口

ACC_ABSTRACT

0x0400

是否为abstract类型,对于接口和抽象类,此标志为真,其它类为假

ACC_SYNTHETIC

0x1000

标识别这个类并非由用户代码产生

ACC_ANNOTATION

0x2000

标识这是一个注解

ACC_ENUM

0x4000

标识这是一个枚举

 

基于地点的报表,测量试验类的拜望标识0x0021= 0x0001 | 0x0020 =ACC_PUBLIC |
ACC_SUPER 

 

5. 类或接口访问标记

代表类还是接口方面包车型大巴访问消息,比如Class表示的是类照旧接口,是还是不是为public、static、final等。,下边我们就来会见TestClass的拜会标识。Class的拜候标识值为0×0021:

图片 37

凭仗前边说的各种访谈标识的标识位,大家能够通晓:0×0021=0×0001|0×0020
也即ACC_PUBLIC 和
ACC_SUPER为真,其中ACC_PUBLIC大家好精通,ACC_SUPE安德拉是jdk1.2后头编写翻译的类都会含有的阐明。

图片 38

5.类索引、父类索引和接口索引群集

 

图片 39

 

Class文件中由那3项数据来鲜明那一个类的三番五次关系

this_class:类索引,用于鲜明这几个类的全限制名,占2字节

super_class:父类索引,用于分明那一个类父类的全限制名(Java语言不相同意多种世襲,故父类索引独有三个。除了java.lang.Object类之外全部类都有父类,故除了java.lang.Object类之外,全体类该字段值都不为0),占2字节

interfaces_count:接口索引流速计,占2字节。借使此类未有兑现其余接口,则该流速计值为0,何况前边的接口的目录群集将不占用别的字节,

interfaces:接口索引集合,一组u2类型数据的成团。用来描述这一个类达成了怎么接口,那几个被实现的接口将按implements语句(要是此类自个儿为接口,则为extends语句)后的接口顺序从左至右排列在接口的目录集结中

this_class、super_class与interfaces中保留的索引值均指向常量池中八个CONSTANT_Class_info类型的常量,通过这一个常量中保留的索引值能够找到定义在CONSTANT_Utf8_info类型的常量中的全节制名字符串

this_class的值为0x0001,即常量池中第2个常量,super_class的值为0x0003,即常量池中的第多个常量,interfaces_counts的值为0x0000,故接口索引集合大小为0

6. 类索引、父类索引与接口索引集结

Class文件中由那3项数据来分明类的三回九转关系。

类索引和父类索引都以指向常量池中的常量索引:

图片 40

紧接着前边是三个接口的流速計和接口描述符:

图片 41

6.字段表集合

字段表用于描述接口也许类中扬言的变量,富含类级变量和实例级变量(是还是不是是static卡塔尔,但不富含在方式内部宣称的一些变量。

 

图片 42

fields_count:字段表流量计,即字段表集结中的字段表数据个数。占2字节,其值为0x0001,即唯有三个字段表数据,也正是测验类中只含有一个变量(不算方法内部变量)

fields:字段表会集,一组字段表类型数据的集纳。字段表用于描述接口或类中扬言的变量,包罗类等级(static)和实例品级变量,不满含在点子内部宣称的变量

在Java中貌似经过如下几项描述二个字段:字段成效域(public、protected、private修饰符)、是类品级变量照旧实例品级变量(static修饰符)、可变性(final修饰符)、并发可以看到性(volatile修饰符)、可种类化与否(transient修饰符)、字段数据类型(基本项目、对象、数组)甚至字段名称。在字段表中,变量修饰符使用标识位代表,字段数据类型和字段名称则引用常量池中常量表示,字段表格式如下表所示:

类型

名称

数量

u2

access_flags

1

u2

name_index

1

u2

descriptor_index

1

u2

attributes_count

1

attribute_info

attributes

attributes_count

 

字段修饰符放在access_flags中,占2字节,其值为0x0002,可以知道这些字段由private修饰,与拜望标记位十三分相像

标志名称

标志值

含义

ACC_PUBLIC

0x0001

字段是否为public

ACC_PRIVATE

0x0002

字段是否为private

ACC_PROTECTED

0x0004

字段是否为protected

ACC_STATIC

0x0008

字段是否为static

ACC_FINAL

0x0010

字段是否为final

ACC_VOLATILE

0x0040

字段是否为volatile

ACC_TRANSIENT

0x0080

字段是否为transient

ACC_SYNTHETIC

0x1000

字段是否为编译器自动产生

ACC_ENUM

0x4000

字段是否为enum

7. 字段表集结

效果:描述接口恐怕类中宣示的类变量以至实例变量,不包涵方法中的局地变量。

随后接口索引集结之后的2字节是字段流速计:

图片 43

意味着我们类中有3个字段,这里正是subInt、subString、subObject
3个字段。紧接其后的是字段表,字段表布局为:

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

图片 44

access_flags项的值是用于定义字段被访谈权限和根底属性的掩码标识。取值范围如下表:

图片 45

呈报符标志字符含义:

图片 46

V 代表极度类型void。

对此数组类型,每贰个维度将运用七个停放的”[“字符来描述,如叁个概念的”java.lang.String[][]“类型的二维数组,将被记录为:”[[Ljava/lang/String;”,贰个整型数组”int[]“将被记录为”[I”

父类中的字段不会并发在子类的字段表中。

7.方法表集结

图片 47

methods_count:方法表流速計,即方法表集结中的法门表数据个数。占2字节,其值为0x0002,即测验类中有2个点子(还自行伸张了一个结构函数)

methods:方法表集结,一组方法表类型数据的聚合。方法表结商谈字段表布局相仿:

类型

名称

数量

u2

access_flags

1

u2

name_index

1

u2

descriptor_index

1

u2

attributes_count

1

attribute_info

attributes

attributes_count

数码项的意义非常帅似,仅在访问标识位和天性表集合中的可选项上有稍稍差别

由于ACC_VOLATILE标志和ACC_TRANSIENT标识不可能修饰方法,所以access_flags中不带有这两项,同不常候扩大ACC_SYNCHRONIZED标志、ACC_NATIVE标志、ACC_STRICTFP标志和ACC_ABSTRACT标志

标志名称

标志值

含义

ACC_PUBLIC

0x0001

字段是否为public

ACC_PRIVATE

0x0002

字段是否为private

ACC_PROTECTED

0x0004

字段是否为protected

ACC_STATIC

0x0008

字段是否为static

ACC_FINAL

0x0010

字段是否为final

ACC_SYNCHRONIZED

0x0020

字段是否为synchronized

ACC_BRIDGE

0x0040

方法是否是由编译器产生的桥接方法

ACC_VARARGS

0x0080

方法是否接受不定参数

ACC_NATIVE

0x0100

字段是否为native

ACC_ABSTRACT

0x0400

字段是否为abstract

ACC_STRICTFP

0x0800

字段是否为strictfp

ACC_SYNTHETIC

0x1000

字段是否为编译器自动产生

 

先是个主意(由编写翻译器自动抬高的暗许布局方法):

图片 48

access_flags为0x0001,即public;name_index为0x0007,即常量池中第7个常量;descriptor_index为0x0008,即常量池中第8个常量

[plain] view
plaincopy图片 49图片 50

 

 

  1. const #7 = Asciz        <init>;  
  2. const #8 = Asciz        ()V;  

图片 51

接下去2个字节为属性流速計,其值为0x0001,表达这么些艺术的属性表集结中有叁天质量,属性名为接下去2位0x0009,指向常量池中第9个常量:Code。接下来4位为0x0000002F,表示Code属性值的字节长度为47。接下来2位为0x0001,表示该形式的操作数栈的纵深最大值为1。接下来2位依旧为0x0001,表示该方法的一部分变量占用空间为1。接下来4位为0x0000005,则跟着的5个字节0x2AB7000AB1为该方式编写翻译后生成的字节码指令(各字节对应的吩咐不介绍了,可查询设想机字节码指令表)。接下来2个字节为0x0000,表达Code属性分外表集结为空。

图片 52

接下去2个字节为0x0002,表明Code属性带有2个性情,那么接下去2位0x000C即为Code属性第三个属性的性质名称,指向常量池中第13个常量:LineNumberTable。接下来4位为0x00000006,表示LineNumberTable属性值所占字节长度为6。接下来2位为0x0001,即该line_number_table中独有二个line_number_info表,start_pc为0x0000,line_number为0x0003,LineNumberTable属性结束。

图片 53

接下去2位0x000D为Code属性第3个属性的属性名,指向常量池中第十二个常量:LocalVariableTable。该属性值所占的字节长度为0x0000000C=12。接下来2位为0x0001,表达local_variable_table中独有一个local_variable_info表,按照local_variable_info表结构,start_pc为0x0000,length为0x0005,name_index为0x000E,指向常量池中第16个常量:this,descriptor_index为0x000F,指向常量池中第18个常量:Lcom/test/Test;,index为0x0000。第三个法子截至

第一个点子:

图片 54

access_flags为0x0001,即public;name_index为0x0010,即常量池中第14个常量;descriptor_index为0x0011,即常量池中第十六个常量

[plain] view
plaincopy图片 55图片 56

 

 

  1. const #16 = Asciz       getM;  
  2. const #17 = Asciz       ()I;  

图片 57

接下去2个字节为属性流速计,其值为0x0001,表达这几个点子有一个办法属性,属性名称叫接下去2位0x0009,指向常量池中第9个常量:Code。接下来4位为0x00000031,表示Code属性值的字节长度为49。接下来2位为0x0002,表示该形式的操作数栈的纵深最大值为2。接下来2位为0x0001,表示该方法的有个别变量占用空间为1。接下来4位为0x0000007,则跟着的7个字节0x2AB400120460AC为该方式编写翻译后生成的字节码指令。接下来2个字节为0x0000,表达Code属性万分表集结为空。

图片 58

接下去2个字节为0x0002,表达Code属性带有2个个性,那么接下去2位0x000C即为Code属性第三个属性的属性名称,指向常量池中第十叁个常量:LineNumberTable。接下来4位为0x00000006,表示LineNumberTable属性值所占字节长度为6。接下来2位为0x0001,即该line_number_table中独有八个line_number_info表,start_pc为0x0000,line_number为0x0007,LineNumberTable属性甘休。

图片 59

和率先个法子的LocalVariableTable属性基本相同,独一的分歧是某些变量this的功能范围覆盖的长短为7并非5,第贰个点子甘休

设若子类未有重写父类的章程,方法表集合中就不会并发父类方法的音信;有相当的大大概会产出由编写翻译器自动抬高的艺术(如:<init>,实例类构造器)

在Java语言中,重载三个办法除了要求和原方法具有雷同的简便名称外,还必要必得持有二个与原方法不相同的特性签字(方法参数会集),由于脾性签字不分包再次回到值,故Java语言中无法仅仅依赖再次来到值的不等对叁个已有个别艺术重载;可是在Class文件格式中,特征签字即为方法描述符,只假设描述符不完全相仿的2个方法也得以合法共存,即2个除了再次来到值不一样之外完全相符的秘技在Class文件中也足以合法共存

javap工具在后半片段会列出分析到位的法子(能够看见和我们的剖释结果是同一的):

[plain] view
plaincopy图片 60图片 61

 

 

  1. d:>javap -verbose Test  
  2. ……  
  3. {  
  4. public com.test.Test();  
  5.   Code:  
  6.    Stack=1, Locals=1, Args_size=1  
  7.    0:   aload_0  
  8.    1:   invokespecial   #10; //Method java/lang/Object.”<init>”:()V  
  9.    4:   return  
  10.   LineNumberTable:  
  11.    line 3: 0  
  12.   
  13.   LocalVariableTable:  
  14.    Start  Length  Slot  Name   Signature  
  15.    0      5      0    this       Lcom/test/Test;  
  16.   
  17. public int getM();  
  18.   Code:  
  19.    Stack=2, Locals=1, Args_size=1  
  20.    0:   aload_0  
  21.    1:   getfield        #18; //Field m:I  
  22.    4:   iconst_1  
  23.    5:   iadd  
  24.    6:   ireturn  
  25.   LineNumberTable:  
  26.    line 7: 0  
  27.   
  28.   LocalVariableTable:  
  29.    Start  Length  Slot  Name   Signature  
  30.    0      7      0    this       Lcom/test/Test;  
  31. }  

 

8. 方法表集结

字段表集合达成后正是方法表集结。

意义:描述该类中的方法。

和字段表同样,使用贰个u2类型的办法流量计,记录该类中艺术的个数。

图片 62

表示大家的类中有9个艺术。

方法表的布局如下图所示

图片 63

其中name_index和descriptor_index表示的是措施的称呼和描述符,他们各自是指向常量池的目录。这里需求结解释一下方法的描述符,方法的叙说符的布局为:(参数列表)重回值,比方public
int instanceMethod(int
param卡塔尔国的描述符为:(I)I,表示带有三个int类型参数且重临值也为int类型的法子,方法java.lang.String.toString(卡塔尔的陈述符为”(卡塔尔(قطر‎Ljava/lang/String;”,int
IndexOf(char[] source,int sourceOffset,int sourceCount,char[] target
int targetOffset,int targetCount,int fromIndex)
表示为([CII[CIIState of QatarI。接下来正是属性数据以致属性表了,方法表和字段表即使都有属性数量和属性表,可是他们个中所含有的习性是例外。

图片 64

倘诺父类方法在子类中一向不被重写(@Override),方法表中就不会不由自主来自父类的主意新闻。

8.属性表集结

在Class文件、属性表、方法表中都能够富含自身的属性表集合,用于描述有些场景的专有消息

与Class文件中其余数据项对长度、顺序、格式的严酷必要不一致,属性表会集不必要当中含有的属性表具备从严的相继,並且只要属性的称呼不与已有个别属性名称再度,任何人完结的编译器能够向属性表中写入自个儿定义的习性新闻。设想机在运维时会忽视不可能识其他属性,为了能准确深入分析Class文件,设想机标准中预约义了设想机实现必得能够辨识的9项属性:

属性名称

使用位置

含义

Code

方法表

Java代码编译成的字节码指令

ConstantValue

字段表

final关键字定义的常量值

Deprecated

类文件、字段表、方法表

被声明为deprecated的方法和字段

Exceptions

方法表

方法抛出的异常

InnerClasses

类文件

内部类列表

LineNumberTale

Code属性

Java源码的行号与字节码指令的对应关系

LocalVariableTable

Code属性

方法的局部变量描述

SourceFile

类文件

源文件名称

Synthetic

类文件、方法表、字段表

标识方法或字段是由编译器自动生成的

种种属性均有分别的表构造。那9种表构造有多个联机的本性,即均由五个u2类型的属性名称起先,能够透过那脾个性名称来判段属性的花色

Code属性:Java程序方法体中的代码通过Javac编写翻译器处理后,最后形成字节码指令存款和储蓄在Code属性中。当然不是统筹的方式都必需有其一特性(接口中的方法或抽象方法就不真实Code属性),Code属性表布局如下:

类型

名称

数量

u2

attribute_name_index

1

u4

attribute_length

1

u2

max_stack

1

u2

max_locals

1

u4

code_length

1

u1

code

code_length

u2

exception_table_length

1

exception_info

exception_table

exception_table_length

u2

attributes_count

1

attribute_info

attributes

attributes_count

 

max_stack:操作数栈深度最大值,在方式试行的任曾几何时刻,操作数栈深度都不会超越这一个值。设想机运营时根据这么些值来分配栈帧的操作数栈深度

max_locals:局部变量表所需寄放空间,单位为Slot(参见备注四)。实际不是有所片段变量占用的Slot之和,当三个部分变量的生命周期甘休后,其所占领的Slot将分配给其余还是存活的一些变量使用,按此情势测算出方法运维时部分变量表所需的蕴藏空间

code_length和code:用来寄存在Java源程序编写翻译后生成的字节码指令。code_length代表字节码长度,code是用于存款和储蓄字节码指令的一两种字节流。

每叁个发令是一个u1档期的顺序的单字节,当虚构机读到code中的二个字节码(二个字节约表示256种指令,Java虚构机标准定义了里面约200个编码对应的指令),就足以决断出该字节码代表的通令,指令后边是还是不是含有参数,参数该如何解释,尽管code_length占4个字节,不过Java设想机标准中约束一个主意不可能超越65535条字节码指令,如若超过,Javac将谢绝编写翻译

ConstantValue属性:布告设想机自动为静态变量赋值,独有被static关键字修饰的变量(类变量)才得以利用那项属性。其组织如下:

类型

名称

数量

u2

attribute_name_index

1

u4

attribute_length

1

u2

constantvalue_index

1

可以观望ConstantValue属性是三个定长属性,个中attribute_length的值固定为0x00000002,constantvalue_index为一常量池字面量类型常量索引(Class文件格式的常量类型中唯有与宗旨项目和字符串类型相呼应的字面量常量,所以ConstantValue属性只协助中央项目和字符串类型)

对非static类型变量(实例变量,如:int a =
123;)的赋值是在实例布局器<init>方法中张开的

对类变量(如:static int a =
123;)的赋值有2种接纳,在类布局器<clinit>方法中或选拔ConstantValue属性。当前Javac编写翻译器的挑肥拣瘦是:假使变量同一时候被static和final修饰(设想机标准只必要有ConstantValue属性的字段必须设置ACC_STATIC标志,对final关键字的渴求是Javac编写翻译器自身出席的须求),何况该变量的数据类型为骨干项目或字符串类型,就生成ConstantValue属性实行初阶化;不然在类布局器<clinit>方法中打开初步化

Exceptions属性:列举出艺术中大概抛出的受查格外(即方法描述时throws关键字后列出的不胜),与Code属性寒级,与Code属性包涵的百般表区别,其协会为:

类型

名称

数量

u2

attribute_name_index

1

u4

attribute_length

1

u2

number_of_exceptions

1

u2

exception_index_table

number_of_exceptions

 

 

 

number_of_exceptions代表只怕抛出number_of_exceptions种受查至极

exception_index_table为那多少个目录集结,一组u2类型exception_index的集合,每一个exception_index为三个针对性常量池中一CONSTANT_Class_info型常量的目录,代表该受查非常的品类

InnerClasses属性:该属性用于记录内部类和宿主类之间的关联。若是一个类中定义了里面类,编写翻译器将会为这些类与这么些类满含的内部类生成InnerClasses属性,布局为:

类型

名称

数量

u2

attribute_name_index

1

u4

attribute_length

1

u2

number_of_classes

1

inner_classes_info

inner_classes

number_of_classes

inner_classes为内部类表会集,一组内部类表类型数据的集聚,number_of_classes即为集结中内部类表类型数据的个数

每一个里边类的音信都由八个inner_classes_info表来说述,inner_classes_info表结构如下:

类型

名称

数量

u2

inner_class_info_index

1

u2

outer_class_info_index

1

u2

inner_name_index

1

u2

inner_name_access_flags

1

inner_class_info_index和outer_class_info_index指向常量池中CONSTANT_Class_info类型常量索引,该CONSTANT_Class_info类型常量指向常量池中CONSTANT_Utf8_info类型常量,分别为内部类的全约束名和宿主类的全约束名

inner_name_index指向常量池中CONSTANT_Utf8_info类型常量的目录,为内部类名称,假诺为无名内部类,则该值为0

inner_name_access_flags类似于access_flags,是内项目标拜谒标识

标志名称

标志值

含义

ACC_PUBLIC

0x0001

内部类是否为public

ACC_PRIVATE

0x0002

内部类是否为private

ACC_PROTECTED

0x0004

内部类是否为protected

ACC_STATIC

0x0008

内部类是否为static

ACC_FINAL

0x0010

内部类是否为final

ACC_INTERFACE

0x0020

内部类是否为一个接口

ACC_ABSTRACT

0x0400

内部类是否为abstract

ACC_SYNTHETIC

0x1000

内部类是否为编译器自动产生

ACC_ANNOTATION

0x4000

内部类是否是一个注解

ACC_ENUM

0x4000

内部类是否是一个枚举

LineNumberTale属性:用于描述Java源码的行号与字节码行号之间的呼应关系,非运转时必得属性,会私下认可生成至Class文件中,还不错Javac的-g:none或-g:lines关闭或必要扭转该项属性音讯,其布局如下:

类型

名称

数量

u2

attribute_name_index

1

u4

attribute_length

1

u2

line_number_table_length

1

line_number_info

line_number_table

line_number_table_length

line_number_table是一组line_number_info类型数据的聚合,其所蕴藏的line_number_info类型数据的多寡为line_number_table_length,line_number_info布局如下:

类型

名称

数量

说明

u2

start_pc

1

字节码行号

u2

line_number

1

Java源码行号

不生成该属性的最大影响是:1,抛出非常时,客栈将不会来得出错的行号;2,调节和测量试验程序时心有余而力不足依据源码设置断点

LocalVariableTable属性:用于描述栈帧中部分变量表中的变量与Java源码中定义的变量之间的关系,非运转时必得属性,暗中同意不会生成至Class文件中,能够选拔Javac的-g:none或-g:vars关闭或必要转变该项属性音信,其构造如下:

类型

名称

数量

u2

attribute_name_index

1

u4

attribute_length

1

u2

local_variable_table_length

1

local_variable_info

local_variable_table

local_variable_table_length

local_variable_table是一组local_variable_info类型数据的集聚,其所包罗的local_variable_info类型数据的数目为local_variable_table_length,local_variable_info构造如下:

类型

名称

数量

说明

u2

start_pc

1

局部变量的生命周期开始的字节码偏移量

u2

length

1

局部变量作用范围覆盖的长度

u2

name_index

1

指向常量池中CONSTANT_Utf8_info类型常量的索引,局部变量名称

u2

descriptor_index

1

指向常量池中CONSTANT_Utf8_info类型常量的索引,局部变量描述符

u2

index

1

局部变量在栈帧局部变量表中Slot的位置,如果这个变量的数据类型为64位类型(long或double),

它占用的Slot为index和index+1这2个位置

start_pc + length即为该有的变量在字节码中的作用域范围

不生成该属性的最大影响是:1,当其余人援用那么些艺术时,全数的参数名称都将错过,IDE大概会利用诸如arg0、arg1等等的占位符代替原有的参数名称,对代码运营无影响,会给代码的编辑带给不方便;2,调节和测量检验时调节和测验器不只怕依照参数名称从运营上下文中获取参数值

SourceFile属性:用于记录生成这一个Class文件的源码文件名称,为可筛选,可以利用Javac的-g:none或-g:source关闭或供给扭转该项属性新闻,其协会如下:

名称

数量

u2

attribute_name_index

1

u4

attribute_length

1

u2

sourcefile_index

1

能够看到SourceFile属性是二个定长属性,sourcefile_index是指向常量池中一CONSTANT_Utf8_info类型常量的目录,常量的值为源码文件的文书名

对大多数文本,类名和文书名是同等的,少数生面别开类除却(如:内部类),那个时候假诺不生成那项属性,当抛出极度时,货仓中校不会显得出错误代码所属的文书名

Deprecated属性和Synthetic属性:那多少个属性都归于标记类型的布尔属性,只存在有和还没有的界别,没有属性值的概念

Deprecated属性表示有些类、字段或格局已经被前后相继作者定为不再推荐使用,可在代码中应用@Deprecated评释举行设置

Synthetic属性表示该字段或措施不是由Java源码直接发生的,而是由编写翻译器自行加多的(当然也可设置访谈标记中的ACC_SYNTHETIC标识,全部由非客户代码发生的类、方法和字段都应有起码设置Synthetic属性和ACC_SYNTHETIC标识位中的一项,独一的不等是实例结构器<init>和类结构器<clinit>方法)

这两项属性的结构为(当然attribute_length的值必得为0x00000000卡塔尔(قطر‎:

类型

名称

数量

u2

attribute_name_index

1

u4

attribute_length

1

图片 65

初步2位为0x0001,表明有三个类属性。接下来2位为属性的名目,0x0014,指向常量池中第十多个常量:SourceFile。接下来4位为0x00000002,表明属性体长度为2字节。最终2个字节为0x0014,指向常量池中第18个常量:Test.java,即这么些Class文件的源码文件名称为Test.java

 

PS:

1,全限制名:将类全名中的“.”替换为“/”,为了确认保证多个三番一回的全约束名之间不发生模糊,在结尾加上“;”表示全约束名甘休。举例:”com.test.Test”类的全节制名叫”com/test/Test;”

2,轻易名称:没有项目和参数修饰的措施或字段名称。比如:”public void
add(int a,int b卡塔尔{…}”该措施的简短名字为”add”,”int a =
123;”该字段的简易名为”a”

3,描述符:描述字段的数据类型、方法的参数列表(富含数据、类型和顺序)和重临值。根据描述符法则,基本数据类型和象征无再次回到值的void类型都用三个大写字符表示,而目的类型则用字符L加对象全节制名表示

标识字符

含义

B

基本类型byte

C

基本类型char

D

基本类型double

F

基本类型float

I

基本类型int

J

基本类型long

S

基本类型short

Z

基本类型boolean

V

特殊类型void

L

对象类型,如:Ljava/lang/Object;

对此数组类型,每一维将使用三个置于的“[”字符来描述,如:”int[]”将被记录为”[I”,”String[][]”将被记录为”[[Ljava/lang/String;”

用描述符描述方法时,遵照先参数列表,后再次回到值的各样描述,参数列表依据参数的严谨各样放在一组”(卡塔尔国”之内,如:方法”String
getAll(int id,String
name卡塔尔”的叙说符为”(I,Ljava/lang/String;State of QatarLjava/lang/String;”

4,Slot,设想机为局地变量分配内部存款和储蓄器所使用的非常小单位,长度不超越三十陆人的数据类型占用1个Slot,陆十一人的数据类型(long和double)占用2个Slot

9. 属性表集结

下边包车型客车情势表中我们就看到<init>方法有一个Code的属性。在本节咱们将解说那几个属性:

Code属性:

该属性里第一寄存由javac编写翻译器管理后获得的字节码指令。

图片 66

其中attribute_name_index指向常量池中值为Code的常量,attribute_length的尺寸表示Code属性表的尺寸(这里
必要注意的时候长度不包蕴attribute_name_index和attribute_length的6个字节的长短)。

max_stack表示最大栈深度,设想机在运行时依照这几个值来分配栈帧中操作数的深度,而max_locals代表了有些变量表所需的蕴藏空间。

max_locals的单位为slot,slot是虚构机为局部变量分配内部存款和储蓄器的一丁点儿单元,在运作时,对于不超过30个人类型的数据类型,比方byte,char,int等占用1个slot,而double和Long这种62人的数据类型则须要分配2个slot,其余max_locals的值实际不是具有片段变量所急需的内部存款和储蓄器数量之和,因为slot是可以援引的,当部分变量当先了它的作用域今后,局地变量所占用的slot就能被选取。方法参数、突显非常微电脑的参数、方法体中定义的片段变量都要动用部分变量表来寄放。

code_length代表了字节码指令的多少,而code表示的是字节码指令,从上海教室能够领会code的类型为u1,贰个u1门类的取值为0x00-0xFF,对应的十进制为0-255,近些日子虚构机标准已经定义了200多条指令。

exception_table_length以及exception_table分别代表办法对应的可怜新闻。

attributes_count和attribute_info分别表示了Code属性中的属性数据和属性表,今后处可以见到Class的公文布局中,属性表是很灵巧的,它能够存在于Class文件,方法表,字段表以致Code属性中。

更正一下Sub中的InterB方法:

 @Override

    public int interB(int i){
        int x=0;
        try{
            x+=i;
            return x;
        }catch(Exception e){
            x=-1;
            return x;
        }finally{
            x=3;
        }
    }

世家不要紧先猜一下以此函数的结果是怎样?假如在try块中发出万分,构造又是什么样?笔者深信对Java语言熟练的对象,料定领会答案。

接受反编写翻译工具查看:

public int interB(int);

    flags: ACC_PUBLIC

    Code:

      stack=2, locals=6, args_size=2

         0: iconst_0

         1: istore_2

         2: iload_2

         3: iload_1

         4: iadd

         5: istore_2

         6: iload_2

         7: istore        5

         9: iconst_3

        10: istore_2

        11: iload         5

        13: ireturn

        14: astore_3

        15: iconst_m1

        16: istore_2

        17: iload_2

        18: istore        5

        20: iconst_3

        21: istore_2

        22: iload         5

        24: ireturn

        25: astore        4

        27: iconst_3

        28: istore_2

        29: aload         4

        31: athrow

      Exception table:

         from    to   target    type

             2       9       14         Class java/lang/Exception

             2       9       25         any

            14      20    25         any

      LineNumberTable:

        line 35: 0

        line 37: 2

        line 38: 6

        line 43: 9

        line 38: 11

        line 39: 14

        line 40: 15

        line 41: 17

        line 43: 20

        line 41: 22

        line 42: 25

        line 43: 27

        line 44: 29

      LocalVariableTable:

        Start  Length  Slot  Name   Signature

               0      32        0      this         Lcom/gissky/clazz/Sub;

               0      32        1        i             I

               2      30        2        x            I

              15    10        3        e            Ljava/lang/Exception;

      StackMapTable: number_of_entries = 2

           frame_type = 255 /* full_frame */

          offset_delta = 14

          locals = [ class com/gissky/clazz/Sub, int, int ]

          stack = [ class java/lang/Exception ]

           frame_type = 74 /* same_locals_1_stack_item */

          stack = [ class java/lang/Throwable ]

}

从 args_size=2这条反编译代码,我们能够通晓,在public int
interB(int
i卡塔尔国这几个艺术中有6个部分变量,2个参数,可是我们的函数中显明独有叁个参数么……那是因为编写翻译器会为每一个实例函数包蕴布局器增添二个参数this,在JVM调用该措施的时候会该形参传递三个实参—方法所在对象的自个儿。

Exception table:

from to target type

2 9 14 Class java/lang/Exception

2 9 25 any

14 20 25 any

上表表头表示,当字节码在form行到to行(不包涵to行)现身类型为type的那多少个,则转到第target行继续管理。

从章程的不得了表中,大家得以见见那一个函数有3条实施路线:

此间我们插入解说一下LineNumberTable表的意义:它代表Java源码行号与字节码行号之间的相应关系。

图片 67

绝对来说上海体育场合,我们能清楚的看看那3条门路。

知道了该形式执行的3条路子,大家也就清楚刚刚我们的卓殊标题有3个答案:未有极度是为x+i;try块中冒出Exception类型的乖谬时,重临-1;现身Exception以外的其他极度方法非经常截止,未有再次回到值。

LocalVariableTable:

Start Length Slot Name Signature

0 32 0 this Lcom/gissky/clazz/Sub;

0 32 1 i I

2 30 2 x I

15 10 3 e Ljava/lang/Exception;

LocalVariableTable表示局地变量表,描述方法中有些变量。

假若你对回到的答案能领略的话,那么小编言听计行你也无可置疑理解,大家函数中唯有4个参数,但max_locals却等于6。不懂的话留意看一下Code中字节码的实施进程变能够知晓了。

三个艺术在实行时须求多大的一部分变量空间在编写翻译时代就清楚了,方法实行时期不会退换部分变量表的大大小小。

Signature 属性:

该属性是在JDK1.5剧增的。该属性可用于类、属性表和办法表构造的属性表中。使用泛型具名如若含有了品种变量(Type
Variables)或参数化类型(Parameterized Types),则Signature
属性会为它记录泛型具名消息。当大家要泛型类中得到泛型的其实类型的时候比非常的低价。

图片 68

实例:

在采用Hibernate时,作者习于旧贯将为Dao层封装三个泛型基类,来放置一些通用的措施,而Hibernate有多数主意都要传递二个POJO的项目,然后开展询问,如load方法。我们营造这样的三个基类:

public abstract class BaseDaoImpl<T, PK extends Serializable>
extends HibernateDaoSupport implements BaseDao<T, PK>

那么load中要选取的POJO类型便是T的实际上类型。怎么来那倒那性子格呢?这里边要使用到Signature属性了。

public abstract class BaseDaoImpl<T, PK extends Serializable> extends HibernateDaoSupport implements BaseDao<T, PK> {

    private Class<T> entityClass;

    @SuppressWarnings("unchecked")
    public BaseDaoImpl() {
        //class OrgDao extends BaseDaoImpl<Organization, String> implements OrgDao {}
        Class c = this.getClass(); //返回的是使用new创建的泛型类对应的对象的class对象。
        Type type = c.getGenericSuperclass(); //取得该对象的泛型类
        //取得泛型对应的真正的class,并放到数组中
        Type[] types = ((ParameterizedType)type).getActualTypeArguments();
        entityClass = (Class<T>) types[0];
    }

那时候,getById中就足以向来利用了:

    public T getById(PK id) {
        return (T) getHibernateTemplate().load(entityClass, id);
    }
You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图