字节码文件详解
1. 以正确的姿势打开文件
字节码文件中保存了源代码编译之后的内容,以二进制的方式存储,无法直接用记事本打开阅读。
通过NotePad++使用十六进制插件查看class文件:
无法解读出文件里包含的内容,推荐使用 jclasslib工具查看字节码文件。
Github地址: https://github.com/ingokegel/jclasslib
可以使用idea下载插件
2. 字节码的组成
字节码文件总共可以分为以下几个部分:
基础信息,常量池,字段,方法,属性
2.1 基础信息
基础信息:魔数、字节码文件对应的Java版本号、访问标识(public final等等)、父类和接口信息
-
Magic魔数
每个Java字节码文件的前四个字节是固定的,用16进制表示就是0xcafebabe。文件是无法通过文件扩展名来确定文件类型的,文件扩展名可以随意修改不影响文件的内容。软件会使用文件的头几个字节(文件头)去校验文件的类型,如果软件不支持该种类型就会出错。
比如常见的文件格式校验方式如下:
Java字节码文件中,将文件头称为magic魔数。Java虚拟机会校验字节码文件的前四个字节是不是0xcafebabe,如果不是,该字节码文件就无法正常使用,Java虚拟机会抛出对应的错误。 -
主副版本号
主副版本号指的是编译字节码文件时使用的JDK版本号,主版本号用来标识大版本号,JDK1.0-1.1使用了45.0-45.3,JDK1.2是46之后每升级一个大版本就加1;副版本号是当主版本号相同时作为区分不同版本的标识,一般只需要关心主版本号。
1.2之后大版本号计算方法就是 : 主版本号 – 44,比如主版本号52就是JDK8。
版本号的作用 主要是判断当前字节码的版本和运行时的JDK是否兼容。如果使用较低版本的JDK去运行较高版本JDK的字节码文件,会报错误 -
其他基础信息
其他基础信息包括访问标识、类和接口索引,如下:
2.2 常量池
常量池: 保存了字符串常量、类或接口名、字段名,主要在字节码指令中使用
字节码文件中常量池的作用:避免相同的内容重复定义,节省空间。
常量池存放两大类常量:字面量和符号引用。
字面量:字面量就是指由字母、数字等构成的字符串或者数值常量。
符号引用可以是:
类和接口的全限定名 com.xx.User
2.3 字段
字段: 当前类或接口声明的字段信息
字段中存放的是当前类或接口声明的字段信息。
如下图中,定义了两个字段a1和a2,这两个字段就会出现在字段这部分内容中。同时还包含字段的名字、描述符(字段的类型)、访问标识(public/private static final等)。
2.4 方法
方法: 当前类或接口声明的方法信息,核心内容为方法的字节码指令
字节码中的方法区域是存放字节码指令的核心位置,字节码指令的内容存放在方法的Code属性中。
2.5 属性
属性: 类的属性,比如源码的文件名、内部类的列表等