@pastqing
2015-09-17T16:00:03.000000Z
字数 2440
阅读 2641
java
下图可以体现java虚拟机提供的语言无关性:
类型 | 名称 | 数量 |
---|---|---|
u4 | magic(魔数) | 1 |
u2 | minior_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 |
u2 | fields | fields_count |
无符号数u1、 u2、 u4、 u8分别代表1个字节,2个字节,4个字节, 8个字节。xxx_info代表表结构。
魔数: class文件的前4个字节称为魔数, 它的作用是用来确定此文件是否可以成为一个能被该虚拟机接受的class文件。魔数的值是0xCAFEBABE
随意打开一个class文件,我们可以看到开头的4个字节是魔数
接下来的4个字节是关于Class的版本信息, 前两个是次版本号, 后两个字节是主版本号。上图的0x31(10进制是49)就是主版本号, 代表JDK1.6, 0000是此版本号。我们有时候会碰到编译器提示JDK错误版本号的信息,可以通过class文件来查看相应的版本号。
使用javap -verbose xx.class命令可以看到class文件常量池中所有的常量:
public class App {
}
它只被关键字public修饰, 则它的access_flags的值应该为:0x0001 | 0x0020 = 0x0021
这里需要注意ACC_SUPER这个标志在JDK1.2以后的版本编译都为真
类索引、父类索引与接口索引集合
类索引(this_class)、父类索引(super_class)分别是两个u2类型的数据, 它们各自指向了一个CONSTANT_Class_info类型的常量, 通过这个常量来其CONSTANT_Utf8_info常量,从而确定这个类和其父类的类名。
从super_class的数量为1这个方面来看, 反映了java 不允许多重继承的特点。super_class的值除了Object类外, 其他的都不为0;
接口索引包括两部分,一个是interfaces_count作为接口的计数器, 一个是interfaces相当于前面的父类索引与类索引。
字段表集合(field_info)
字段表集合用来描述类或者接口中声明的变量。这个变量包括的是类变量和实例变量, 但是不包括方法内部声明的局部变量, 下面是字段表集合的结构:
字段的修饰关键字放在access_flags中,与之前的访问标志相似。可以设置的字段访问标志有:
name_index也与前面的类似,是对常量池的索引, 代表了字段的简单名称(方法名,变量名)
descriptor_index是用来描述字段的数据类型(int, char...), 方法的参数列表(数量,类型, 顺序)和 返回值。下面列出描述符标志字符的含义:
标识字符 含义 标识字符 含义 B byte J long C char S short D double Z boolean F float V void I int L 对象类型,如Ljava/lang/String
比如String[][]可以表述出: [[Ljava/lang/String;,
int indexOf(int a, char b)可以描述为: (IB)I