代码敲了很久,但是一直没有怎么去研究他的整个的过,最近有时间就研究了一下,总结后就写了JVM系列的博客,以便总结与回顾。
java从编码到执行的过程如下图一所示:
java 文件通过 javac 编译后成 class 文件,class 文件由 classLoader 加载进 JVM ,加载后由字节码解释器解释后交给执行引擎,最后由执行引擎交给操作系统供其调用 。当某个文件执行的非常平凡的时候就会由JIT(即时编译器)编译,下次再执行的时候就不要解释器再一句一句的解释执行,效率会高很多。一般情况下都是混合模式,通过 java -version可以查看,如下图二:
接下来就是就开始进入正题了,ClassFileFormat 到底是什么呢?其实就是class文件的格式,接下来我就作详细的介绍。我写一个简单的java类,如下图三:
public class Demo1 {
int i = 0;
String s = "Hello ByteCode!";
public Demo1(int i, String s) {
this.i = i;
this.s = s;
}
public void m() {}
}
我们再通过插件 BinEd-Binary 插件打开Demo1.class 文件,如下图四所示:
或许直接看16进制的看不明白,没关系,我,二面还可以用 jclasslib 插件打开Demo1.class 文件,如下图五所示:
这里我们就看见了一个class文件的大概轮廓,还有javap -v + class文件全限定名 也可以达到相同的效果。在《深入理解java虚拟机》的第六章第二节里面就可以看到对class文件格式的诠释。如下:
- class文件“基本类型表一
u1 | 1个字节,无符号类型 |
u2 | 2个字节,无符号类型 |
u4 |
4个字节,无符号类型 |
u8 | 8个字节,无符号类型 |
- ClassFile 表的格式表二
类型 | 名称 | 数量 |
---|---|---|
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 | thsi_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 |
attributes_info | attributes | attributes_count |
ClassFile 表中各项简介如下:
- magic(魔数)
每个Java class 文件的前4个字节被称为他的魔数(magic number):0x CAFEBABE (图四的前四个字节)。魔数的作用在于,可以轻松的分辨出java class文件和非java class 文件。如果一个文件不是以0xCAFEBABE 开头的,那他肯定不是java class文件。 - minnor_version 和 major_version
class文件的下面4个字节包含了主、次版本号。随着Java 技术的发展,java class 文件格式可能会加入新特性。class 文件格式一旦发生变化,版本号也会随之变化。对于java 虚拟机来说,版本号确定了特定的class文件格式,通常只有给定主版本号和一系列次版本号后,java虚拟机才能够读取class文件。如果class文件的版本号超出了java虚拟机所能处理的有效范围,java虚拟机不会处理该class文件。jdk 1.8 的版本号是 52. - constant_pool.count 和 constant_pool
class 文件中,魔数和版本号后面的是常量池。常量池包含了与文件中类和接口相关的常量。常量池中存储了诸如文字字符串、final 变量值、类名和方法名的常量。常量池标志如下表三 :入口类型 标志值 描述 CONSTANT_Utf8 1 UTF-8 编码的Unicode字符串 CONSTANT_Integer 3 int类型字面值 CONSTANT_Float 4 float 类型字面值 CONSTANT_Long 5 long类型字面值 CONSTANT_Double 6 double 类型字面值 CONSTANT_Class 7 对一个类或接口的符号引用 CONSTANT_String 8 string 类型字面值 CONSTANT_Fieldref 9 对一个字段的符号引用 CONSTANT_Methodref 10 对一个类中声明的方法的符号引用 CONSTANT_InterfaceMethodref 11 对一个接口中声明的方法的符号引用 CONSTANT_NameAndType 12 对一个字段或方法的部分符号引用 - access_flags
紧接常量池后面的两个字节称为 access_flags ,他展示了文件中定义的类或接口的几段信息。classFile表内access_flags的标志位如下表四:标志名 值 设置后的含义 设置名 ACC_PUBLIC 0x0001 public 类型 类和接口 ACC_FINAL 0x0010 类为final类型 只有类 ACC_SUPER 0x0020 使用新型的invokespecial语义 类和接口 ACC_INTERFACE 0x0200 接口类型,不是类 类型 所有的接口,没有类 ACC_ABSTRACT 0x0400 abstract类型 所有的接口,部分类 - this_class
接下来的两个字节为this_class项,它是一个队常量池的索引。例如:图五右边的 this_class,浅绿色的 cp_info #5 就是指向常量池的第五个常量,然后继续指向常量池的第26个常量,就得到了类的全限定名 - super_class
在class文件中,紧接在this_class 之后的是 super_class 项,它是一个两个字节的常量池索引。与this_class类似,直接查看图五右边的 super_class 即可 - interfaces_count 和 intefaces
紧接着 super_class 的是 interfaces_count。此项的含义为:在文件中该类直接实现或者由接口所扩展的父接口的数量。在这个计数的后面,是名为 interfaces 的数组,它包含了对每个由该类或者接口直接实现的父接口的常量池索引。 - fields_count 和 fields
在class文件中,紧接在 interfaces 后面的是对在该类或者接口中所声明的字段的描述。首先是名为 fields_count 的计数,它是类变量和实例变量的字段的数量总和。在这个计数后面的是不同长度的 field_info 表的序列。只有在文件中由类或者接口声明了的字段才能在 fields 列表中列出。在 fields 列表中,不列出从超类或者父接口继承而来的字段。另一方面,fields 列表可能会包含在对应的java源文件中没有叙述的字段,这是因为java编译器可能会在编译时向类或者接口添加字段,添加进去的字段使用 Synthetic 属性标识。fields_descriptor 标识对应如下表五所示:B byte
C char D double F float I int J long S short Z boolean V void L Object [ array(例如:[B ,表示 byte[] [Ljava/lang/String 表示 string[] ,多维数组 [[C [[[Ljava/lang/String) - methods_count 和 methods
在class文件中紧接着fields 后面的是对该类或者接口中所声明的方法的描述。首先是名为 methods_count 的计数,它是一个双字节长度的对于该类或者接口中声明的所有方法的总计数。这个总计数只包含在该类或者接口中显式定义的方法(从超类或者父接口中集成来的方法不被计入)。在metnod_count 后面的是方法的本身,他在一个 methid_info 表的列表中进行了阐述(methids_count 指出了列表中有多少个method_info 表)。如下图五所示:
还有就是方法里面的逻辑运算等,如下图六所示:
圈出的这部分内容其实就是java 的汇编语言,在 jvms 8 的第六、七章有说明,jvms 的下载地址为 https://docs.oracle.com/javase/specs/index.html,值得注意的是一定要注意版本。 - <()V>代表的是方法 m 的参数类型和返回值类型,例子给出的是无参和无返回值,所以是这个样子。
- attributes_count 和 attributes
class 文件中最后的部分是属性(attribute),他给出了在改文件中类或者接口所定义的属性的基本信息。属性部分由 attributes_count 开始,attributes_count 是指出现在后续 attributes 列表中的 attributes_info 表的数量总和。每个 attributes_info 的第一项是指向常量池中 CONSTANT_Utf8_info表的索引,该表给出了属性的名称。
这次ClassFileFormat就介绍到这里,如果有不正确地 地方还望大佬指正,谢谢!