代码编译的结果从本地机器码转变为字节码。
字节码构成平台无关性的基石
实现与厌恶惯性的基础是虚拟机和字节码的存储格式
Java虚拟机不与任何语言绑定,只与Class文件这种特定的二进制文件格式关联。
虚拟机把Java代码或其他支持的语言的代码编译为存储字节码的Class文件。
Class类文件
Class文件十一组以8位字节为基础单位的二进制流
Class类文件构成
- 1. 头四个字节称为魔数,用来确定这个文件是否为一个能被虚拟机接受的Class文件
- 2. 紧接着魔数的四个字节存储Class文件的版本号 5,6为次版本号 7,8为主版本号
- 主次版本号之后是3. 常量池入口 常量池主要存放两大类常量:
- 字面量
字面值常量即我们在程序中定义的字符串、被final修饰的值。 - 符号引用
符号引用就是我们定义的各种名字:- 类和接口的全限定名
- 字段的名字 和 描述符
- 方法的名字 和 描述符
- 字面量
常量池的特点
- 常量池长度不固定
- 常量池的大小是不固定的,因此常量池开头放置一个u2类型的无符号数,用来存储当前常量池的容量。JVM根据这个值就知道常量池的头尾来。
注:这个值是从1开始的,若为5表示池中有4个常量。 - 常量池中每一个常量都是一个表
常量池开头有个常量池容量计数器,接下来就全是一个个常量了,只不过常量都是由一张张二维表构成,除了记录常量的值以外,还记录当前常量的相关信息。 - 常量池是class文件的资源仓库
- 常量池是与本class中其它部分关联最多的部分
- 常量池是class文件中空间占用最大的部分之一
常量池的14种表开始的第一位是一个u1类型的标志位 tag 代表当前这个常量属于那种常量类型。
以CONSTANT_Class_info为例
类型 | 名称 | 数量 |
---|---|---|
u1 | tag | 1 |
u2 | name_index | 1 |
tag表示当前常量的类型,name_index标识这个类或接口全限定名的位置 它的值表示指向常量池的第几个常量如指向 CONSTANT_Utf8_info 常量
CONSTANT_Utf8_info表:
类型 | 名称 | 数量 |
---|---|---|
u1 | tag | 1 |
u2 | length | 1 |
u1 | bytes | length |
tag表示当前常量的类型,这里应该是1;
length表示这个字符串的长度;
bytes为这个字符串的内容(采用缩略的UTF8编码)
Q:为什么Java中定义的类、变量名字必须小于64K?
A: 类、接口、变量等名字都属于符号引用,它们都存储在常量池中。而不管哪种符号引用,它们的名字都由CONSTANT_Utf8_info类型的常量表示,这种类型的常量使用u2存储字符串的长度。由于2字节最多能表示65535个数,因此这些名字的最大长度最多只能是64K。
Q:什么是UTF-8编码?什么是缩略UTF-8编码
A:前者每个字符使用3个字节表示,而后者把128个ASKII码用1字节表示,某些字符用2字节表示,某些字符用3字节表示。
- 4.访问标志 常量池结束之后紧接着的两个字节代表访问标志 ,用于识别一些类或者接口层次的访问信息,包括:这个Class是类还是接口,是否定义为public类型,是否定义为abstract类型,是类的话是否声明为final等。