微信公众号【Java技术江湖】一位阿里 Java 工程师的技术小站。(关注公众号后回复”Java“即可领取 Java基础、进阶、项目和架构师等免费学习资料,更有数据库、分布式、微服务等热门技术学习视频,内容丰富,兼顾原理和实践,另外也将赠送作者原创的Java学习指南、Java程序员面试指南等干货资源)
Java的代码可以一次编译,到处运行,是因为JVM可以识别class文件,JVM虚拟机和物理机的效果是一样的,有一套指令集让代码翻译成对应的操作,只不过JVM指令集最终还要去执行物理机的指令集,比如X86。
JVM指令集简介
oolong编程语言是一种汇编语言,我们可以将class文件先转化为oolong汇编语言,以便理解。实际上JVM直接基于字节码运行,不需要经过中间的汇编过程,但是我们依然可以先把它翻译成汇编,这些汇编代码可以很好地对应JVM提供的指令集。
如果直接用class文件去匹配jvm指令集,肯定是不太现实的。
与类相关的指令
这部分指令主要与类信息相关,譬如原文件名,类名,父类,以及修饰符等等,一般类中的操作都有对应的JVM指令相对应(这里的指令指的是汇编指令)
方法的定义
方法的定义包括修饰符,方法名,操作函数等等,也有其对应的指令。比如invokervirtual调用实例方法。
属性的定义
属性定义包括了数据类型,方法的修饰属性,类的修饰属性,等等。
其他指令集
由于JVM的指令集是基于栈进行操作的,所以也有与栈操作相关的指令集,还有与运算相关,与数组操作相关的指令集等等。
这里也有我们熟悉的同步操作相关指令集,monitor enter和monitor out,这个汇编指令可以帮助jvm完成同步操作。
class文件头的表示形式
class文件的内容是顺序排列的。
第一行是一个标识符,是”cafebabe”,表明这个文件是一个class文件。
后面两个字节表示版本分为。
所以前6个字节是表示class文件的基本头信息,jvm加载class时会检查其是否符合条件。
常量池
接下来到了常量池部分。
第一行有两个字节表示该类中含有常量的总数,有十几种类型
这些常量通常都是相互引用的。
基本数据类型
Integer,Float,Long等等
UTF-8常量类型
一般用于存储字符串值
fieldref、methodref
这两个类型很明显是为了描述class中的属性项和方法的,如何表示一个class中的属性和方法呢,比如fieldref,前两个字节表示是哪个类中的field,后面两个字节表示这个fieldref的name和type。
methodref和fieldref也类似。
所以methodref和fieldref存的是类名称和nameandtype
class常量类型
class常量表示的是该类的名称,会指向另一个UTF-8类型的常量来存储具体名称,因为名称是字符串啦。
所以class常量中存的是索引。
nameandtype
nameandtype是为了表达methodref和fieldref的名称和类型描述才存在的,名称通常用utf8来表示,类型描述也用utf8来表示。
所以nameandtype主要包含两个utf8的位置索引
类信息
常量列表的后面就是类本身的信息描述了。比如这个类的访问控制。名称和类型,以及父类信息等。
fields和methods定义
类信息描述后面就是每个fields和methods的具体定义了,刚才的methodref和fieldref其实就是索引到了这一部分的内容。
类属性描述
和field和method一样,class同样也有附加属性描述。
javap生成的class文件结构
除了通过oolong生成class文件格式,也可以通过javap来生产class文件格式。这个文件格式更容易理解。