Learn · concepts
什么是 ASM(Java 字节码)?库详解
ASM 是一個在執行時讀取和寫入 JVM 字節碼的 Java 庫。以下是其功能、工作原理以及為什麼 Minecraft 模組依賴它的原因.
什么是 Minecraft 模组开发中的 ASM?
ASM 是一个 Java 库,用于读取、修改和写入 JVM 字节码。它直接处理编译后的 .class 文件,而不是源代码,因此可以在不重新编译的情况下检查或重写类。Minecraft 模组依赖于它,因为它允许它们在游戏加载时修补游戏,即使游戏已经编译完成。
为什么存在字节码修补
Minecraft 游戏以编译后的字节码形式发布,而不是源代码。这意味着模组作者无法修改源代码并重新编译整个游戏:源代码不存在。修补你未拥有的代码的唯一方法是在字节码级别进行操作,即 Java 虚拟机实际运行的指令集。ASM 是完成这项工作的实用工具。
ASM 的工作原理
ASM 将编译后的类转换为程序可以编辑的内容。一个 .class 文件仅仅是字节码,即 Java 虚拟机运行的指令。ASM 解析这些字节码,将方法和字段交给你,并允许你添加、删除或更改指令。然后,它将一个新的有效类写回。
纯 Java 本身无法做到这一点。编译器将你的源代码编译成字节码一次,之后字节码就被固定了。ASM 在字节码级别进行操作,这低于你通常编写的源代码层。
访问者模式和树 API
ASM 读取一个类,使用 ClassReader,并写入一个类,使用 ClassWriter。 在两者之间,你的代码会访问类的各个部分并决定要进行哪些更改。 有两种方法:
访问者模式 逐个元素地流过类。 这种方法速度快且内存占用少,因为它从不持有整个类。 树模式 将类加载到你可以自由行走和编辑的对象中,这对于较大的更改来说更容易理解,但会占用更多内存。
| 方法 | 工作方式 | 适用场景 |
|---|---|---|
| 访问者 API | 流式读取类事件 | 小而快速的编辑,内存占用低 |
| 树 API | 构建类的可编辑对象模型 | 更大或更复杂的重写 |
为什么 Minecraft 模组使用 ASM
模组需要更改他们没有编写且无法重新编译的游戏代码。 游戏以编译后的类形式发布,因此唯一的入口点是字节码级别,而 ASM 正是提供了这一点。 模组可以在游戏方法中注入钩子,重定向调用或添加字段,所有这些都在启动时完成。
大多数模组制作者不会直接调用 ASM。 他们使用 Mixin,这是一个位于 ASM 之上的高级框架,可以将简单的注释转换为底层的字节码编辑。 你编写一个小的 Java 类来描述更改,框架会为你处理 ASM 的底层工作。 Fabric 模组尤其依赖于此链.
当你需要直接接触 ASM 时
作为模组作者,你很少会直接编写原始 ASM 代码。它通常出现在工具需要比注释所能表达的更多控制权时,例如加载器、混淆器或重写整个类的补丁程序。对于日常模组来说,顶层的注释层就足够了,而且出错的可能性要小得多.
常见问题
不。反编译器将字节码转换回可读的源代码。ASM 直接操作字节码,旨在修改它,而不是恢复源代码.
通常不是。大多数 Fabric 模组使用 Mixin,它通过注解隐藏了 ASM 的细节。只有在需要精细控制时,你才需要直接使用 ASM.
ASM 并非一个特定的工具,而是一套通用的 Java 库,被广泛应用于处理字节码的各种工具中。其中,Minecraft 模组开发是 ASM 的一个常见应用,但并非唯一的用途.
你不能。游戏以编译好的形式发布,而不是你可以修改和重新编译的源代码。编辑字节码是修改你未拥有代码的实际方法.