1 编译阶段
1.1 编译器和虚拟机
Java编译器的作用是将xx.java Java源代码编译成class文件
Java编译器是独立于Java虚拟机外部的,它不是Java虚拟机的一部分
不仅仅有Java编译器,同样存在其他语言的编译器,可以将其他语言的源代码生成.class文件
Java虚拟机不和任何语言绑定,他只和class文件这种特定的二进制文件格式所有关联,它并不关心class文件的来源是什么,任何方式生成的class文件,即便是利用十六进制自行编写的有效class文件,都可以在Java虚拟机上运行
1.2 无关性
1.2.1 平台无关性
Java的平台无关性:各种不同平台的虚拟机与所有平台都可以执行同一个java文件,原因就在于编译器编译出的class文件是一种字节码文件
[class文件和字节码文件]
A 首先字节码的概念:是一种包含执行程序,由一序列代码/数据对组成的二进制文件,是一种中间码
B class文件就是一种字节码文件,之所以叫class文件是因为编译结果的后缀名是.class,其本质上还是字节码文件
C 在Java虚拟机中这两个名称表示的都是java源代码编译后的结果,常常混着叫
1.2.2 语言无关性
Java虚拟机的语言无关性,就是在于它只在乎class文件这种二进制格式,至于它是什么语言编译出来的,它都不care
2 class类文件结构
2.1 class文件是什么
class文件是一组以8字节为基础单位的二进制流,各个数据项目按照顺序紧凑排列,中间没有任何分隔符,存放的都是程序运行的必要数据。
如果遇到需要占用8个字节以上空间的数据项会按照”高位在前”的方式分割成若干8字节存储
如果必要信息存放完毕之后,class类文件大小不是8的整数倍,则需要在最后以0补齐
1 任何一个class文件中都存放着唯一一个接口或者类的定义信息,但是类和接口不一定都定义在文件里,比如定义类中引用的其他类是由类加载器生成的(类加载器看运行阶段的博客)
2 class文件不一定是以磁盘文件存在的具体文件,它可以在JAR包等ZIp格式中读取,还可以在网络中获取、利用动态代理在运算时生成、由其他文件生成(比如Jsp文件)、从数据库中读取………
2.2 class文件格式
class文件格式采用一种伪结构存储数据,在这种伪结构中只有两种数据类型:无符号数 和 表
1 无符号数:是基本的数据类型,以u1、u2、u4、u8代表1 2 4 8个字节的无符号数
理解:
其实就是二进制,以二进制0 1 的形式,我们常见的编译后的class文件常以十六进制打开,也就是u1:两位十六进制、u2:四位十六进制、u4:八位十六进制、u8:十六位十六进制
[一个字节8为二进制、4位二进制=一位十六进制、一个字节两位十六进制 0x23这样的格式]
class文件是二进制流,里面都是二进制的形式,任何数字、常量、值等等都是二进制表示的
2 表:表是由多个符号数或者其他表作为数据项构成的复合数据类型
理解:
表的概念就像List集合一样,可以容纳多个常量值,还可以再容纳list
举个例子像一个Student的属性,有多个无符号数表示的姓名、年级、性别等,还可以有一个同样为表的课程,里面存放了多个用无符号数表示的课程名
PS:class文件格式中有哪些表是文件规范规定好的,哪些变量需要存放在哪个表里都是格式规定好的,和程序员本身是没有关系的
3 无论是无符号数还是表,当需要描述同一类型但数量不多的多个数据时,需要使用一个前置的容量计数器加若干连续数据项的形式
理解:
XX容量计数器 数据1 数据2 ……….数据n
XX容量计数器的值就是后面接着数据的数量,他表示在后面多少单位开始就不是范围内的数据了
这里需要注意的常量池容量计数是从下标1开始的,如果后面有21个数据,常量池容量计数值要赋值22表示从1到21
其他容量是从下标0开始,赋值21表示从0-20都是范围内数据
2.3 class文件结构
Class类的总体结构即如上图所示,魔术、版本号、常量表、访问控制、父类索引、接口集合、字段表、方法表所组成
有一些基本的魔数、版本号什么的就不再说明,选择一些特别需要注意的,其他的需要时再去看书好了
常量池计数值
和其他的XX计数值不同,常量池的计数值是从1开始的,上文中也说过了
另外计数值是开区间,如果包含x,则要赋值x+1;
父类索引
Java中除了Object类之外都是有父类的,未说明extends的它的父类是Object
索引
结构中的各种索引,父类索引也好、名字索引也好指向的都是常量池中各种常量表