欢迎光临散文网 会员登陆 & 注册

Java ASM详解:基础知识

2020-07-23 13:50 作者:Nickid2018  | 我要投稿

由于很久没有投稿了,想了想还是发专栏吧!

之前一直在做虚拟化学实验室的程序,由于感觉不太舒服,重构了很多遍,并加入了亿点点内容,其中就有包括ASM的知识。由于网上的文章很碎,重复率也是很高,所以我打算自己来写一个。

首先第一个问题:

ASM是什么,字节码又是什么

ASM是一个Java字节码分析、创建和修改的开源应用框架。它可以动态生成二进制格式的stub类或其他代理类,或者在类被Java虚拟机装入内存之前,动态修改类。在ASM中提供了诸多的API用于对类的内容进行字节码操作的方法。与传统的BCEL和SERL不同,在ASM中提供了更为优雅和灵活的操作字节码的方式。

这是ASM官网上给出的没用解释,一句话概括:ASM是一个修改,分析Java类文件的框架。先抛开ASM框架的基本定义,先来看看字节码是什么

字节码(Byte-code)是一种包含执行程序,由一序列 op 代码/数据对组成的二进制文件

又是一段废话。从这里可以的知,字节码是一种介于翻译语言和底层语言的东西,与底层语言(C/C++)相比较你可以从它这里知道程序的运行方式,而对于翻译语言(JS)你又无法从字节码中轻易看出什么。但是由于字节码的这个特性,我们得以修改它,操纵它,并且我们还可以反编译它。

前提知识说完,开始真正的了解。

ASM的图标

官网:https://asm.ow2.io/?FORM=UCIAST&pname=shenma

添加ASM库依赖

首先,是有关于ASM的Maven依赖

<dependency>

     <groupId>org.ow2.asm</groupId>

     <artifactId>asm-all</artifactId>

     <version>6.0_BETA</version>

</dependency>

现在的ASM版本已经来到了6.0_BETA版本,如果你用的是asm,asm-tree这样组合也能达到相同效果。这个库以后会详细讲述,这里先说几个强有力的工具。

帮助学习ASM的工具

1.ASMifier:自动生成ASM代码
ASM库中有不少实用类,为了了解晦涩难懂的ASM代码,可以用ASMifier来进行解析。这是一个可执行类,你可以通过java.exe运行它。

运行方法:下载ASM的jar(比如asm-all-6.0_BETa.jar)或者从你的.m2文件夹里面找到它,然后运行:

java -classpath asm-all-6.0_BETA.jar org.objectweb.asm.util.ASMifier DemoDump.class

你会得到这样的输出:

图源:https://www.jianshu.com/p/905be2a9a700,原作者用的是5.2版本

2.javap.exe:Java自带的字节码解析工具

javap是你在安装JDK时就有的一个程序文件,是JDK的原生字节码解析工具,关于它的使用因篇幅有限不再细说,可以参考这篇文章 https://www.cnblogs.com/frinder6/articles/5440173.html

上方是有关于直接查看字节码的,下方则是反编译的工具

3.Eclipse插件:Enhanced Class Decompiler

这个插件是反编译器,可以在你没有库的源代码时反编译出源代码进行调试。当然,这个也可以作为你ASM程序的结果测试方案,通常反编译结果会很贴近于源代码,如果相差很大可以换一种方式反编译。

下面是有关于以后经常会用到的名词,这些对于学习ASM都极其重要。

类(型)的不同名称

类的二进制名称/类全名/简单名称

这个三个名称是等价的,也就是我们平常说的类名,例如 java.lang.Thread java.lang.Thread$UncaughtExceptionHandler这样的名称。

全限定名

这个名称是用于class文件中的名称,其实就是将二进制名称的所有"."换为"/",这个名称只有非数组引用类型才有。例如 java/lang/Thread   java/io/IOException。

类型描述符

类型描述符是有关于class文件内定义字段等的类型的名称,它遵循以下规则:

1.原始类型的描述符一一对应

原始类型的描述符都对应相应的一个字母,具体来说是这样的:

byte -> B

short -> S

int -> I

long -> J

float -> F

double -> D

char -> C

void -> V

boolean -> Z

2.非数组的引用类型为 L+全限定名+;

3.数组引用类型为 [+数组内类型的描述符

例子:

java.lang.Thread -> Ljava/lang/Thread;

java.lang.Object[] -> [Ljava/lang/Object;

int[][] -> [[I

方法描述符

了解类名称和类型描述符,下面讲一下方法描述符(其实字段描述符和方法描述符统称描述符)

方法描述符是class文件中保存参数类型列表和返回值类型的方式,在各种方法调用的操作码里面都会涉及到。

规则:

1.格式为 ( + 参数列表 + ) + 返回值

2.所有类型名称都为类型描述符

3.参数列表中不需要逗号分隔

下面是抽象含义下的具体例子(省略了参数名称,只保留了参数类型):

void a(int,int,int) -> (III)V

String s(double[],boolean) -> 

                            ([DZ)Ljava/lang/String;

int[] i(Object) -> (Ljava/lang/Object;)[I

void t() -> ()V

操作码(OpCode)

Opcode是用于JVM解释运行Java程序的关键。每一个Opcode都有自己独特的含义与操作,如0x60,助记符iadd,将两个int相加。

有一点要注意:操作码其实就是一个数字,我们平时经常看到的iadd,invokestatic并不是操作码,而是助记符。

而Java中字节码的名称也与操作码有关,因为每个操作码都是用一个字节,所以叫字节码。

每一个字节用来表示一个指令,理论上可以有 256 个操作码。

对于ASM库来说,所有的Opcode都存储于org.objectweb.asm.Opcodes里面,其中还有包括它们在什么方法中作用的注释。

有关于所有操作码的网页:https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html?FORM=UCIAST&pname=shenma


这就是有关于ASM的基础知识,有些没有说到的东西会在以后的专栏中说到。

如果文章中有任何错误,可以在评论区留言,我将会修正错误。

这篇文章稍后也会在CSDN上同步。

P.S.由于这篇专栏是我用手机写的,所以没有配图,排版也有可能有问题,下一篇专栏还是用电脑写。

参考文章:

字节码-搜狗百科 https://baike.sogou.com/m/v53858822.htm

ASM 库的介绍和使用 -  lijiankun24 - 简书 https://www.jianshu.com/p/905be2a9a700

全限定名、简单名称和描述符是什么东西?https://www.cnblogs.com/wxdlut/articles/12229562.html

bytecode 和 opcode 是什么?有什么区别? https://segmentfault.com/q/1010000009643588/a-1020000009643956

Java ASM详解:基础知识的评论 (共 条)

分享到微博请遵守国家法律