把之前的笔记重新整理了一下,发上来供对java class文件结构的有兴趣的同学参考一下,也算对以前知识的回顾。
java class文件打破了c或者c++等语言所遵循的传统,用这些传统语言写的程序通常首先被编译,然后被连接成单独的、专门支持特定硬件平台和操作系统的二进制文件。通常情况下,一个平台上的二进制可执行文件不能在其他平台上工作。
java class文件是可以运行在任何支持java虚拟机的硬件平台和操作系统上的二进制文件,class文件中包含了java虚拟机指令集和符号表以及若干其他辅助信息。作为一个通用的、机器无关的执行平台,任何其他语言的实现者都可以将java虚拟机作为语言的产品交付媒介。例如,使用java编译器可以把java代码编译成存储字节码的class文件,使用grooy等其他语言的编译器一样可以把程序代码编译成class文件,虚拟机并不关心class的来源是何种语言。
class文件是一组以8位字节位基础单位的二进制流,采用一种类似c语言结构体的伪结构来存储数据,这种伪结构只有两种数据类型:<code>无符号数</code>和<code>表</code>。无符号数属于基本的数据类型,以u1、u2、u4、u8分别代表1个字节、2个字节、4个字节、8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或utf-8编码构成的字符串值。表是由多个无符号数或其他表作为数据项构成的复合数据类型,所有表都习惯性地以_info结尾。
每一个 class 文件对应于一个如下所示的 classfile 结构体:
借用下之前同学的图能更清晰地表达:
本文以testclasscode.class源码为例展开,testclasscode.java对应的java代码如下:
testclasscode.class对应的字节码如下:
constant pool:
#1 = class #2 // com/test/doc/exp/testclasscode
#2 = utf8 com/test/doc/exp/testclasscode
#3 = class #4 // java/lang/object
#4 = utf8 java/lang/object
#5 = utf8 attribute_1
#6 = utf8 ljava/lang/string;
#7 = utf8 attribute_2
#8 = utf8 ljava/lang/integer;
#9 = utf8
#10 = utf8 ()v
#11 = utf8 code
#12 = methodref #3.#13 // java/lang/object."":()v
#13 = nameandtype #9:#10 // "":()v
#14 = utf8 linenumbertable
#15 = utf8 localvariabletable
#16 = utf8 this
#17 = utf8 lcom/test/doc/exp/testclasscode;
#18 = utf8 testinterface_1
#19 = utf8 testinterface_2
#20 = utf8 (ljava/lang/string;)ljava/lang/string;
#21 = utf8 param
#22 = utf8 sourcefile
#23 = utf8 testclasscode.java
struct field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes;
}
struct method {
u2 method_counts;
method_info[] method_infos;
struct method_info {
struct attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
struct code {
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
exception_info exception_table;
u2 attribute_count;
struct linenumbertable {
u2 line_number_table_length;
line_number_info line_number_table;