Class文件的结构其实也很简单,主要可通过下面的数据结构表示
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源代码都会生成对应的class文件,文件中最重要的当属constant_pool了,不过首先还是说一下描述符。
A 描述符
Java源代码中有方法、类、域(即成员变量或类变量)几种,这些在Class文件中都有对应的描述符进行描述。例如:
Object method(int i,double d,Thread t)
对应的描述符为:
(IDLjava/lang/Thread;)LJava/Object
格式为(参数描述符*)返回描述符,可以看到函数名称在其中并没有出现。
B 常量池
有了描述符就可以在常量池中对它进行索引了。例如在常量池中包含一种数据结构:
CONSTANT_NameAndType_info {
u1 tag;
u2 name_index;
u2 descriptor_index;
}
用于描述域和方法的
其中descriptor_index会索引到一个Constant_Utf8的字符串,这个字符串可能就是前面所说的"(IDLjava/lang/Thread;)LJava/Object"
其中name_index会索引到一个Constant_Utf8的字符串,它是这个方法或域的不完整限定名。(Thread类的完整限定名是 java.lang.Thread, 不完整限定名是Thread)
C 属性
一些的关注还需要放在attributes上,因为这个数据结构中包含了将要被执行的JVM指令代码,attributes的数据结构如下:
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
这只是一个可变的结构,对于code来说,它能演化为:
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];
}
我们关心的code就放在code的数组中,另外我们看到了一些关于exception的信息,还有最后居然还又嵌入了attributes信息,这些信息可能是LineNumberTable或LocalVariableTable ,这些都是我们可能想知道的一些调试信息,需要在编译时加上"-g"选项。
知道了Class文件的格式就可以使用JVM加载它,并进行校验,准备和解析了,并加载运行指令