# jad [`jad`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials?language=cn&id=command-jad) ::: tip 反编译指定已加载类的源码 ::: `jad` 命令将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码,便于你理解业务逻辑; - 在 Arthas Console 上,反编译出来的源码是带语法高亮的,阅读更方便 - 当然,反编译出来的 java 代码可能会存在语法错误,但不影响你进行阅读理解 ## 参数说明 | 参数名称 | 参数说明 | | --------------------: | :----------------------------------------- | | _class-pattern_ | 类名表达式匹配 | | `[c:]` | 类所属 ClassLoader 的 hashcode | | `[classLoaderClass:]` | 指定执行表达式的 ClassLoader 的 class name | | [E] | 开启正则表达式匹配,默认为通配符匹配 | ## 使用参考 ### 反编译`java.lang.String` ```java $ jad java.lang.String ClassLoader: Location: /* * Decompiled with CFR. */ package java.lang; import java.io.ObjectStreamField; import java.io.Serializable; ... public final class String implements Serializable, Comparable, CharSequence { private final char[] value; private int hash; private static final long serialVersionUID = -6849794470754667710L; private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; public static final Comparator CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator(); ... public String(byte[] byArray, int n, int n2, Charset charset) { /*460*/ if (charset == null) { throw new NullPointerException("charset"); } /*462*/ String.checkBounds(byArray, n, n2); /*463*/ this.value = StringCoding.decode(charset, byArray, n, n2); } ... ``` ### 反编译时只显示源代码 默认情况下,反编译结果里会带有`ClassLoader`信息,通过`--source-only`选项,可以只打印源代码。方便和[mc](mc.md)/[retransform](retransform.md)命令结合使用。 ```java $ jad --source-only demo.MathGame /* * Decompiled with CFR 0_132. */ package demo; import java.io.PrintStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.concurrent.TimeUnit; public class MathGame { private static Random random = new Random(); public int illegalArgumentCount = 0; ... ``` ### 反编译指定的函数 ```java $ jad demo.MathGame main ClassLoader: +-sun.misc.Launcher$AppClassLoader@232204a1 +-sun.misc.Launcher$ExtClassLoader@7f31245a Location: /private/tmp/math-game.jar public static void main(String[] args) throws InterruptedException { MathGame game = new MathGame(); while (true) { /*16*/ game.run(); /*17*/ TimeUnit.SECONDS.sleep(1L); } } ``` ### 反编译时不显示行号 `--lineNumber` 参数默认值为 true,显示指定为 false 则不打印行号。 ```java $ jad demo.MathGame main --lineNumber false ClassLoader: +-sun.misc.Launcher$AppClassLoader@232204a1 +-sun.misc.Launcher$ExtClassLoader@7f31245a Location: /private/tmp/math-game.jar public static void main(String[] args) throws InterruptedException { MathGame game = new MathGame(); while (true) { game.run(); TimeUnit.SECONDS.sleep(1L); } } ``` ### 反编译时指定 ClassLoader ::: tip 当有多个 `ClassLoader` 都加载了这个类时,`jad` 命令会输出对应 `ClassLoader` 实例的 `hashcode`,然后你只需要重新执行 `jad` 命令,并使用参数 `-c ` 就可以反编译指定 ClassLoader 加载的那个类了; ::: ```java $ jad org.apache.log4j.Logger Found more than one class for: org.apache.log4j.Logger, Please use jad -c hashcode org.apache.log4j.Logger HASHCODE CLASSLOADER 69dcaba4 +-monitor's ModuleClassLoader 6e51ad67 +-java.net.URLClassLoader@6e51ad67 +-sun.misc.Launcher$AppClassLoader@6951a712 +-sun.misc.Launcher$ExtClassLoader@6fafc4c2 2bdd9114 +-pandora-qos-service's ModuleClassLoader 4c0df5f8 +-pandora-framework's ModuleClassLoader Affect(row-cnt:0) cost in 38 ms. $ jad org.apache.log4j.Logger -c 69dcaba4 ClassLoader: +-monitor's ModuleClassLoader Location: /Users/admin/app/log4j-1.2.14.jar package org.apache.log4j; import org.apache.log4j.spi.*; public class Logger extends Category { private static final String FQCN; protected Logger(String name) { super(name); } ... Affect(row-cnt:1) cost in 190 ms. ``` 对于只有唯一实例的 ClassLoader 还可以通过`--classLoaderClass`指定 class name,使用起来更加方便: `--classLoaderClass` 的值是 ClassLoader 的类名,只有匹配到唯一的 ClassLoader 实例时才能工作,目的是方便输入通用命令,而`-c `是动态变化的。