计算机是只能识别0和1的,Java的设计者创新性的提出了跨平台的概念,
把Java编译成字节码文件,运行在 jvm虚拟机中,从而可以达到跨平台的概念。
Java只不过是jvm支持的众多语言中的最广泛的一种 ,Java和jvm虚拟机并不是绑定在一起的。
实际上,不论哪种语言,只要他的最终产物编译成字节码,都是可以运行在jvm之上的,例如 groovy,scala,jython 等
字节码查看工具: jclasslib
https://github.com/ingokegel/jclasslib
1. 反编译
命令行工具:
1. javap -verbose
分析 魔数,版本号,常量池,类信息,构造方法,成员方法,变量
2. javap -c xxx
3. 十六进制查看
mac :hex_fiend 。 win :winhex
1. 魔数
字节数: U4
Java采用魔数来识别字节码文件而不是后缀,从而规避安全性风险。
1. class文件的头四个字节是魔数 CA FE BA BE
2. 版本号
字节数: U4
挨着四个字节代表版本号
其中前2字节代表次版本号 minor version,
后2字节代表主版本号 major version
3. 常量池 constant pool
常量池个数的字节数: U2 + N
1. 主版本号之后的是常量池入口,一个Java类中定义的很多信息都是由常量池来维护的,
我们可以将常量池看做class文件的资源库,比如 方法变量信息,
2. 常量池主要存储2中数据, 字面量和符号引用
字面量: 文本字符串,比如final常量值
符号引用:类和接口的全局限定名,字段以及方法的名称和描述符
3. 常量池的总体结构:Java类所对应的常量池主要由常量池数量和常量池数组构成
3. 常量池数量和常量池数组
1. 常量池数量紧跟主版本后,占用2个字节。
2. 常量池数组紧跟常量池数量,与一般数组不同的是,它的元素类型,结构都是不相同 的。
每一种元素的第一个数据都是一个u1类型,该字节是一个标志位,占1个字节,
jvm在解析常量池时,会根据这个u1类型获取元素具体类型,
常量池数组中元素的个数等于 常量池数-1(其中0暂时不使用),目的是满足某些
常量池索引值的数据在特定情况下表达 不引用任何常量池的含义。
根本原因是所以0也是一个常量(保留常量),不过它不位于长量表中,对应null值,
常量池索引从1开始
常量池对照表
字节码整体结构
在jvm规范中,每个变量/字段都有描述信息,描述信息的主要作用就是描述
字段的数据类型,方法的参数列表(数量,类型,顺序)与返回值
基本数据类型和代表返回值void的类型都用一个大写字符标识,对象类型使用L加上
对象的全限定名称来标识,为了压缩字节码体积
基本数据类型都是用一个大写字符标识:
B - byte。C - chart。D - double。 I - int 。J - long。F - float。
z - boolean。V - void。S - short。
L - 对象类型,如 Ljava/lang/String
对于数组: 使用 前置的方括号[ 。如 int ,记录为 [I
二维数组: 使用前置的[[ 记录,比如 [[I
方法的描述符
先参数列表后返回值类型,参数列表按照严格顺序放在一组()内
比如: 方法 String getName(int id,string name)
(I,Ljava/lang/String;)Ljava/lang/String;
4. accessFlag 访问标志
字节数: U2
示例 : 0x0021 是 acce_public 和 acc_super的并集
5. this class Name
字节数: u2
6. super class name
字节数: u2
7. interfaces
字节数: u2 + N
8. fields
字节数: u2 + N
字段表 : 用于描述类和接口中声明的变量。包括类变量和实例变量,但是不包括方法内局部变量
变量由以下几部分信息组成fieldInfo
1. 访问修饰符 U2
2. 名字索引 U2
3. 描述符索引 U2 (类型)
4. attribute count
5. attribute info
9. methods
字节数: U2 + N
方法数量: U2 默认会有一个无参数的构造方法,所以方法+1
方法表 :
1. 访问修饰符 U2
2. 名字索引 U2
3. 描述符索引 U2 (类型)
4. attribute count
5. attribute info
方法属性结构表:
1. 名字索引 U2
2. 属性长度 U4
3. 具体信息 U1
code 结构表:
stack 方法执行的最大栈的深度
local 方法运行期间创建的局部变量的数目,包括入参的局部变量
args_size 至少为1,因为this是隐式传递的
助记符
10. attributes
字节数: U2 + N