什么是字节码以及它的组成
字节码概念
Java 字节码(英语:Java bytecode)是Java虚拟机执行的一种指令格式。
大多数操作码都是一个字节长,而有些操作需要参数,导致了有一些多字节的操作码。
因为JVM针对各种操作系统和平台都进行了定制,无论在什么平台,都可以通过javac命令将一个.java文件编译成固定格式的字节码(.class文件)供JVM使用。之所以被称为字节码,是因为.class文件是由十六进制值组成的,JVM以两个十六进制值为一组,就是以字节为单位进行读取
格式如下
字节码的组成
JVM对字节码的规范是有要求的,要求每一个字节码文件都要有10部分固定的顺序组成:
魔术、版本号、常量池、访问标志、当前类索引、父类索引、接口索引、字段表、方法表、附件属性
详细如下:
- 魔数
所有的.class文件的前4个字节都是魔数,魔数以一个固定值:0xCAFEBABE,放在文件的开头,JVM就可以根据这个文件的开头来判断这个文件是否可能是一个.class文件,如果是以这个开头,才会往后执行下面的操作,这个魔数的固定值是Java之父James Gosling指定的,意为CafeBabe(咖啡宝贝)
- 版本号
版本号是魔术之后的4个字节,前两个字节表示次版本号(Minor Version),后两个字节表示主版本号(Major Version),上面的0000 0032,次版本号0000转为十进制是0,主版本号0032 转为十进制50,对应下图的版本映射关系,可以看到对应的java版本号是1.6
- 常量池
紧接着主版本号之后的字节为常量池入口,常量池中有两类常量:字面量和符号引用,字面量是代码中申明为Final的常量值,符号引用是如类和接口的全局限定名、字段的名称和描述符、方法的名称和描述符。常量池整体分为两个部分:常量池计数器以及常量池数据区
- 访问标志
常量池结束后的两个字节,描述的是类还是接口,以及是否被Public、Abstract、Final等修饰符修饰,JVM规范规定了9种访问标示(Access_Flag)JVM是通过按位或操作来描述所有的访问标示的,比如类的修饰符是Public Final,则对应的访问修饰符的值为ACC_PUBLIC | ACC_FINAL,即0x0001 | 0x0010=0x0011
- 当前类索引
访问标志后的两个字节,描述的是当前类的全限定名,这两个字节保存的值是常量池中的索引值,根据索引值就能在常量池中找到这个类的全限定名
- 父类索引
当前类名后的两个字节,描述的父类的全限定名,也是保存的常量池中的索引值
- 接口索引
父类名称后的两个字节,是接口计数器,描述了该类或者父类实现的接口数量,紧接着的n个字节是所有接口名称的字符串常量的索引值
- 字段表
用于描述类和接口中声明的变量,包含类级别的变量和实例变量,但是不包含方法内部声明的局部变量,字段表也分为两个部分,第一部分是两个字节,描述字段个数,第二部分是每个字段的详细信息fields_info
- 方法表
字段表结束后为方法表,方法表也分为两个部分,第一个部分是两个字节表述方法的个数,第二部分是每个方法的详细信息
方法的访问信息比较复杂,包括方法的访问标志、方法名、方法的描述符和方法的属性:
- 附加属性
字节码的最后一部分,该项存放了在该文件中类或接口所定义属性的基本信息。