Java ASM系列:(003)ASM与ClassFile
本文属于[Java ASM系列一:Core API](https://blog.51cto.com/lsieun/2924583)当中的一篇。
## 1. ClassFile
我们都知道,在`.class`文件中,存储的是ByteCode数据。但是,这些ByteCode数据并不是杂乱无章的,而是遵循一定的数据结构。
![From Java to Class](http://www.icode9.com/i/li/?n=2&i=images/20210618/1624004678130912.jpeg?,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
这个`.class`文件遵循的数据结构就是由[Java Virtual Machine Specification](https://docs.oracle.com/javase/specs/jvms/se8/html/index.html)中定义的
[The class File Format](https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html),如下所示。
```text
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
```
## 2. 字节码类库
ASM是操作字节码的类库,但并不是唯一的,还有许多其它的操作字节码的类库。
### 2.1 常见的字节码类库
在下面列举了几个比较常见的字节码类库:
- [Apache Commons BCEL](https://commons.apache.org/proper/commons-bcel/):其中BCEL为Byte Code Engineering Library首字母的缩写。
- [Javassist](http://www.javassist.org/):Javassist表示**Java** programming **assist**ant
- [ObjectWeb ASM](https://asm.ow2.io/):本课程的研究对象。
- [Byte Buddy](https://bytebuddy.net/):在ASM基础上实现的一个类库。
那么,字节码的类库和ClassFile之间是什么样的关系呢?我们可以用下图来表示:
![字节码类库](http://www.icode9.com/i/li/?n=2&i=images/20210619/1624105555567528.png?,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
对于上图,我们用三句来描述它们的关系:
- 中间层-多个`.class`文件,虽然每个类里面的内容各不相同,但它们里面的内容都称为字节码(ByteCode)。
- 中下层-不论这些`.class`文件内容有怎样大的差异,它们都共同遵守同一个数据结构,即ClassFile。
- 中上层-为了方便于人们对于字节码(ByteCode)内容的操作,逐渐衍生出了各种操作字节码的类库。
- 上下层-不考虑中间层,我们可以说,不同的字节码类库是在同一个ClassFile结构上发展起来的。
既然有多个可以选择的字节码类库,那么我们为什么要选择ASM呢?这就得看ASM自身所有的特点,或者说与众不同的地方了。
### 2.2 ASM的特点
- 问题:与其它的操作Java字节码的类库相比,ASM有哪些与众不同的地方呢?
- 回答:在实现相同的功能前提下,使用ASM,运行速度更快(运行时间短,属于“时间维度”),占用的内存空间更小(内存空间,属于“空间维度”)。
The ASM was designed to be as **fast** and as **small** as possible.
- Being as **fast** as possible is important in order not to slow down too much the applications that use ASM at runtime, for dynamic class generation or transformation.
- And being as **small** as possible is important in order to be used in memory constrained environments, and to avoid bloating the size of small applications or libraries using ASM.
简而言之,ASM的特点就是fast和small。
## 3. ASM与ClassFile的关系
为了大家更直观的理解ASM与ClassFile之间关系,我们用下图来表示。其中,**Java ClassFile相当于“树根”部分,ObjectWeb ASM相当于“树干”部分,而ASM的各种应用场景属于“树枝”或“树叶”部分**。
![ASM与ClassFile的关系](http://www.icode9.com/i/li/?n=2&i=images/20210619/1624105610265567.png?,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
学习ASM有三个不同的层次:
- 第一个层次,ASM的应用层面。也就是说,我们可以使用ASM来做什么呢?对于一个`.class`文件来说,我们可以使用ASM进行analysis、generation和transformation操作。
- 第二个层次,ASM的源码层面。也就是,ASM的代码组织形式,它为分Core API和Tree API的内容。
- 第三个层次,Java ClassFile层面。从JVM规范的角度,来理解`.class`文件的结构,来理解ASM中方法和参数的含义。
![ASM的学习层次](http://www.icode9.com/i/li/?n=2&i=images/20210619/1624105643863231.png?,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
在本次课程当中,会对Class Generation和Class Transformation进行介绍。
- 第二章 生成新的类,是结合Class Generation和`asm.jar`的部分内容来讲。
- 第三章 修改已有的类,是结合Class Transformation和`asm.jar`的部分内容来讲。
- 第四章 工具类和常用类,是结合Class Transformation、`asm-util.jar`和`asm-commons.jar`的内容来讲。
## 4. 总结
本文主要围绕着“ClassFile”和“ASM”展开,内容总结如下:
- 第一点,具体的`.class`文件遵循`ClassFile`的结构。
- 第二点,操作字节码(ByteCode)的类库有多个。ASM是其中一种,它的特点是执行速度快、占用空间小。
- 第三点,ASM与ClassFile之间的关系。形象的来说,ClassFile相当于是“树根”,而ASM相当于是“树干”,而ASM的应用场景相当于“树枝”或“树叶”。
本文的重点是理解“ASM与ClassFile之间的关系”,也不需要记忆任何内容。
正所谓“君子务本,本立而道生”,ClassFile是“根本”,而ASM是在ClassFile这个根本上所衍生出来的一条修改字节码(ByteCode)道路或途径。