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