类文件结构
一、无关性的基石
java通过java虚拟机实现一次编写,到处运行
java 虚拟机不和包括java在内的任何语言绑定,它只与“class 文件”这种特定的二进制文件格式关联,class文件包含了Java虚拟机指令集
和符号表以及其他辅助信息。
二、Class类文件的结构
1、Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑的排列在Class文件中,中间没有任何分隔符;
当遇到占用8位字节以上的空间数据项时,会按照高位在前(大端)的方式分割成若干个8位字节进行存储。
Class文件存储数据类型:无符号数和表
无符号数:基本的数据类型,以u1、u2、u4、u8代表1个字节,2个字节,4个字节,8个字节的无符号数;无符号数可以用来描述数字、索引引用、
数量值、活字符串值。
表:由多个无符号数或者其他表作为数据项构成的复合数据类型,习惯以_info结尾。
Class文件格式
| 类型 |
名称 |
数量 |
| u4 |
magic(魔数:Class文件是否能被虚拟机接受) |
1 |
| u2 |
minor_version(次版本号) |
1 |
| u2 |
major_version(主版本号:jdk 1.7 51.0;1.6 50) |
1 |
| u2 |
constant_pool_count(常量池容量) |
1 |
| cp_info |
constant_pool(常量池:存放字面量(文本字符串等)、符号引用:类、接口全限定名,字段、方法名称和描述符) |
constant_pool_count-1 |
| u2 |
access_flag(访问标志:类还是接口;是否为public、abstract、final等) |
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(属性表集合:描述某些场景专有信息,例如code属性存放方法中的java字节码指令) |
attributes_count |
方法里的Java代码,经过编译器编译成字节码指令后,存放在属性表集合中的Code属性里。
Code属性是Class文件中最重要的一个属性,如果把一个Java程序中的信息分为代码(Code,方法体里面的Java代码)和元数据(Metadata,包括
类、字段、方法定义及其他信息)两部分,那么整个Class文件中,Code属性用于描述代码,所有的其他数据项目都用于描述元数据。
三、字节码指令
Java虚拟机的指令由一个字节长度的、代表特定操作含义的数字(操作码)以及跟随其后的操作所需参(操作数)数构成。
java虚拟机指令集所支持的数据类型
| opcode(操作码) |
byte |
short |
int |
long |
float |
double |
char |
reference |
| Tipush:将一个常量加载到操作数栈 |
bipush |
sipush |
|
|
|
|
|
|
| Tconst |
|
|
iconst |
lconst |
fconst |
dconst |
|
aconst |
| Tload:将一个局部变量加载到操作栈 |
|
|
iload |
lload |
fload |
dload |
|
aload |
| Tstore:将一个数值从操作数栈存储到局部变量表 |
|
|
istore |
lstore |
fstore |
dstore |
|
astore |
| Taload:将一个数组元素加载到操作栈 |
baload |
saload |
iaload |
laload |
faload |
daload |
caload |
aaload |
| Tastore:将一个数值从操作数栈存储到数组元素 |
basotre |
sastore |
iastore |
lastore |
fastore |
dastore |
castore |
aastore |
| Tadd:加法指令 |
|
|
iadd |
ladd |
fadd |
dadd |
|
|
| Tsub:减法指令 |
|
|
isub |
lsub |
fsub |
dsub |
|
|
| Tmul:乘法指令 |
|
|
imul |
lmul |
fmul |
dnul |
|
|
| Tdiv:除法指令 |
|
|
idiv |
ldiv |
fdiv |
ddiv |
|
|
| Trem:求余指令 |
|
|
irem |
lrem |
frem |
drem |
|
|
| Tneg:取反指令 |
|
|
ineg |
lneg |
fneg |
dneg |
|
|
| Tshl:左移指令 |
|
|
ishl |
lshl |
|
|
|
|
| Tshr:右移指令 |
|
|
ishr |
lshr |
|
|
|
|
| Tushr:符号右移指令 |
|
|
iushr |
lushr |
|
|
|
|
| Tor:按位或指令 |
|
|
ior |
lor |
|
|
|
|
| Tand:按位与指令 |
|
|
iand |
land |
|
|
|
|
| Txor:按位异或指令 |
|
|
ixor |
lxor |
|
|
|
|
| i2T:类型转换 |
i2b |
i2s |
|
i2l |
i2f |
i2d |
|
|
| l2T:类型转换 |
|
|
l2i |
|
l2f |
l2d |
|
|
| f2T:类型转换 |
|
|
f2i |
f2l |
|
f2d |
|
|
| d2T:类型转换 |
|
|
d2i |
d2l |
d2f |
|
|
|
| Tcmp:比较指令 |
|
|
|
lcmp |
|
|
|
|
| Tcmpl:比较指令 |
|
|
|
|
fcmpl |
dcmpl |
|
|
| Tcmpg:比较指令 |
|
|
|
|
fcmpg |
dcmpg |
|
|
| if_TcmpOP:控制转移指令 |
|
|
if_icmpOP |
|
|
|
|
|
| Treturn:方法返回指令 |
|
|
ireturn |
lreturn |
freturn |
dreturn |
|
areturn |
除表中指令外还有:
1、对方创建与访问指令:
- 创建类实例指令:new
- 创建数组指令:newarray、anewarray、multianewarray
- 访问类字段(static字段、或者称为类变量)和实例字段(非static字段,或者称为实例变量)指令:getfield、getstatic、putfield、putstatic
- 取数组长度指令:arraylength
- 检查类实例类型指令:instanceof、checkcast
2、操作数栈管理指令:直接操作操作数栈
- 将操作数栈的栈顶一个或两个元素出栈:pop、pop2
- 复制栈顶一个或两个数字并将复制值双份的复制值重新压入栈顶:dup、dup2、dup_x1、dup2_x1、dup_x2、dup2_x2
- 将栈顶端两个数值交换:swap
3、方法调用指令
- invokevirtual:用于调用对象的实例方法,根据对象的实际类型进行分派
- invokeinterface:调用接口方法,在运行时搜索一个实现接口的方法对象,找出适合的方法进调用
- invokespecial:调用一下需要特殊处理的实例方法,包括实例初始化方法、私有方法、父类方法
- invokestatic:调用类方法(static方法)
- invokedynamic:在运行时动态解析出调用点限定符所引用的方法,并执行该方法;