最近开始学习IntelliJ插件开发,于是就把之前维护的一款反编译插件重新实现了一个版本,并且加入了javap指令的支持,对于理解Java class文件有着不错的帮助。
安装下载
源码: https://github.com/work-helper/class-decompile-intellij
JB插件地址: https://plugins.jetbrains.com/plugin/13914-class-decompile
插件功能
插件的使用很简单,对着Java,Kotlin等JVM上语言文件或者是class文件点击右键,选择Show Decompile Code
,即可反编译对应的class文件,如下图所示:
Javap支持
javap
是JDK自带的反编译工具,因此支持需要依赖External Tools
功能支持,如下图所示在对应菜单中配置javap命令入口,插件则会自动调用对应的javap指令进行反编译。
反编译能做什么
理解语法糖
反编译能够还原语法糖的实现,帮助你更好的理解编程语言的本质。比如kotlin下的object class
,反编译后可以很好的理解单例实现。
反编译前
cfr反编译后
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import kotlin.Metadata;
@Metadata(mv={1, 1, 16}, bv={1, 0, 3}, k=1, d1={"。。。。"}) public final class UserService { public static final UserService INSTANCE;
private UserService() { }
static { UserService userService; INSTANCE = userService = new UserService(); } }
|
了解Class文件结构
在插件javap指令参数配置上增加-p -v
,那么反编译能够打印出对应的class文件信息,你可以很清楚的了解的class文件由哪几部分构成。
反编译前
javap反编译后(比较长,省略了很多内容)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| public final class cn.mrdear.test.UserService minor version: 0 major version: 50 flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER Constant pool: #1 = Utf8 cn/mrdear/test/UserService #2 = Class #1 #3 = Utf8 java/lang/Object #4 = Class #3 #5 = Utf8 <init> ...... { public static final cn.mrdear.test.UserService INSTANCE; descriptor: Lcn/mrdear/test/UserService; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
private cn.mrdear.test.UserService(); descriptor: ()V flags: ACC_PRIVATE Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #8 4: return LineNumberTable: line 8: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcn/mrdear/test/UserService;
static {}; descriptor: ()V flags: ACC_STATIC Code: stack=2, locals=1, args_size=0 0: new #2 3: dup 4: invokespecial #26 LineNumberTable: line 8: 0 } SourceFile: "UserService.kt" RuntimeVisibleAnnotations: 0: #13(#14=[I#15,I#15,I#16],#17=[I#15,I#18,I#19],#20=I#15,#21=[s#22],#23=[s#10,s#24,s#6,s#25])
|
学习Java字节码指令
反编译后能够查看到对应的字节码操作,了解dup,ldc,invokespecial,astore_0
等相应字节码在JVM上起到的具体作用。
反编译前
ASM反编译后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public final class cn/mrdear/test/UserService {
@Lkotlin/Metadata;(mv={1, 1, 16}, bv={1, 0, 3}, k=1, d1={"。。。。 "class-decompile-intellij.main"})
// access flags 0x19 public final static Lcn/mrdear/test/UserService; INSTANCE
// access flags 0x2 private <init>()V L0 LINENUMBER 8 L0 ALOAD 0 INVOKESPECIAL java/lang/Object.<init> ()V RETURN L1 LOCALVARIABLE this Lcn/mrdear/test/UserService; L0 L1 0 MAXSTACK = 1 MAXLOCALS = 1
// access flags 0x8 static <clinit>()V L0 LINENUMBER 8 L0 NEW cn/mrdear/test/UserService DUP INVOKESPECIAL cn/mrdear/test/UserService.<init> ()V ASTORE 0 ALOAD 0 PUTSTATIC cn/mrdear/test/UserService.INSTANCE : Lcn/mrdear/test/UserService; RETURN MAXSTACK = 2 MAXLOCALS = 1 }
|
废话不多说,赶快去使用吧。