工欲善其事,必先利其器,推荐几款优秀的工具,让我们学习 ASM 更加简单。


1、jclasslib bytecode viewer

这个工具可以让我们看到编译后 .class 文件的字节码。


在plugins 里搜索并添加应用。

image.png



image.png


image.png


怎么样好用吧?




呸!好用个屁。这玩意说实话真的不咋地。不过能看个大概也算不错。


接下来重点介绍两个极其好用的工具。


2、showByteCode

利用javap命令 通过工具快捷方式来显示出来。


Mac 下 java 的路径: 打开终端,执行 /usr/libexec/java_home -V


image.png


注意前提是先编译。

然后右击出来菜单。

image.png



这就是我们心心念念的的了。

/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/bin/javap -verbose Student
Classfile /Users/a10963/IdeaProjects/Test11/out/production/Test11/Student.class
  Last modified 2019-7-15; size 440 bytes
  MD5 checksum 98d7465b4ddd42ef2c9510ab28f403c5
  Compiled from "Student.java"
public class Student
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#21         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#22         // Student.i:I
   #3 = Class              #23            // Student
   #4 = Class              #24            // java/lang/Object
   #5 = Utf8               i
   #6 = Utf8               I
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               LStudent;
  #14 = Utf8               greaterThen
  #15 = Utf8               (II)I
  #16 = Utf8               intOne
  #17 = Utf8               intTwo
  #18 = Utf8               StackMapTable
  #19 = Utf8               SourceFile
  #20 = Utf8               Student.java
  #21 = NameAndType        #7:#8          // "<init>":()V
  #22 = NameAndType        #5:#6          // i:I
  #23 = Utf8               Student
  #24 = Utf8               java/lang/Object
{
  public int i;
    descriptor: I
    flags: ACC_PUBLIC

  public Student();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: bipush        10
         7: putfield      #2                  // Field i:I
        10: return
      LineNumberTable:
        line 1: 0
        line 3: 4
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      11     0  this   LStudent;

  public int greaterThen(int, int);
    descriptor: (II)I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=3
         0: iload_1
         1: iload_2
         2: if_icmple     7
         5: iconst_0
         6: ireturn
         7: iconst_1
         8: ireturn
      LineNumberTable:
        line 6: 0
        line 7: 5
        line 9: 7
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  this   LStudent;
            0       9     1 intOne   I
            0       9     2 intTwo   I
      StackMapTable: number_of_entries = 1
        frame_type = 7 /* same */
}
SourceFile: "Student.java"

Process finished with exit code 0




3、ASMifier


说实话为了搞出来这个花了半天时间。真的是费老大劲了,因为网上对这个真的是言辞极少,也不说清楚,哎,都是大神啊。

如果是MAC电脑,文字如下记住  两个目录之间用:分割,windows 用;分割。

mac:

java -classpath  /Users/a10963/AOSP/WORKING_DIRECTORY/prebuilts/tools/common/m2/repository/org/ow2/asm/asm/5.1/asm-5.1.jar:/Users/a10963/AOSP/WORKING_DIRECTORY/prebuilts/tools/common/m2/repository/org/ow2/asm/asm/5.1/asm-5.1.jar:asm-util-5.1.jar  jdk.internal.org.objectweb.asm.util.ASMifier  java.lang.Runnable

windows:


java -classpath  /Users/a10963/AOSP/WORKING_DIRECTORY/prebuilts/tools/common/m2/repository/org/ow2/asm/asm/5.1/asm-5.1.jar;/Users/a10963/AOSP/WORKING_DIRECTORY/prebuilts/tools/common/m2/repository/org/ow2/asm/asm/5.1/asm-5.1.jar:asm-util-5.1.jar  jdk.internal.org.objectweb.asm.util.ASMifier  java.lang.Runnable


运行结果是不是我们心心念念的 ASM 代码。 


image.png



4、TraceClassVisitor

当我们通过ASM自己生成代码的时候,如何看到我们的代码呢?这就用到了 TraceClassVisitor。


   ClassWriter cw = new ClassWriter(0);
        TraceClassVisitor cv = new TraceClassVisitor(cw, new PrintWriter(System.out));
        cv.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT + Opcodes.ACC_INTERFACE,
                "test/asm/examples/Comparable", null, "java/lang/Object",
                new String[] { "test/asm/examples/Mesurable" });
        cv.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "LESS", "I", null, new Integer(-1)).visitEnd();
        cv.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "EQUAL", "I", null, new Integer(0)).visitEnd();
        cv.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "GREATER", "I", null, new Integer(1)).visitEnd();
        cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT, "compareTo", "(Ljava/lang/Object;)I", null, null).visitEnd();
        cv.visitEnd();


执行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=52342:/Applications/IntelliJ IDEA CE.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/lib/tools.jar:/Users/a10963/IdeaProjects/Test11/out/production/Test11:/Users/a10963/IdeaProjects/Test11/lib/iplclientobfused.jar Main
// class version 49.0 (49)
// access flags 0x601
public abstract interface test/asm/examples/Comparable implements test/asm/examples/Mesurable  {


  // access flags 0x19
  public final static I LESS = -1

  // access flags 0x19
  public final static I EQUAL = 0

  // access flags 0x19
  public final static I GREATER = 1

  // access flags 0x401
  public abstract compareTo(Ljava/lang/Object;)I
}

Process finished with exit code 0


5、ASM Bytecode Outline


添加 plugin  ASM Bytecode Outline ,右击直接查看ASM源码,简单粗暴。


image.png

image.png