kaka的gravatar头像
kaka 2017-11-03 13:49:56
java字节码分析工具classpy

先附上这个开源工具的地址:https://github.com/zxh0/classpy

我是怎么知道这个工具的呢,前几天我突然想看看foreach底层的实现原理,于是我写了一个demo想看看字节码是什么样的,demo如下;

import java.util.ArrayList;
import java.util.List;

/**
 * @author kaka
 * @create 2017-10-26 15:10
 **/
public class ForeachTest {
    List<Integer> integerList = new ArrayList<>();
    Integer[] args = new Integer[12];
    public void foreachTest(){
        for(Integer i : args){

        }
    }
}

编译后的class文件如果你用文本编辑器打开会是下面这样子的

java字节码分析工具classpy

用命令javap -verbose className可以反编译字节码,比如:

javap -verbose ForeachTest,得到的内容如下

警告: 二进制文件ForeachTest包含com.suninfo.service.test.monitor.ForeachTest
Classfile /E:/workspace/suninfo-api/src/test/java/com/suninfo/service/test/monitor/ForeachTest.class
  Last modified 2017-10-26; size 590 bytes
  MD5 checksum f2817ab03d0e82d8b278c5a8e7a9d7a3
  Compiled from "ForeachTest.java"
public class com.suninfo.service.test.monitor.ForeachTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #8.#24         // java/lang/Object."<init>":()V
   #2 = Class              #25            // java/util/ArrayList
   #3 = Methodref          #2.#24         // java/util/ArrayList."<init>":()V
   #4 = Fieldref           #7.#26         // com/suninfo/service/test/monitor/ForeachTest.integerList:Ljava/util/List;
   #5 = Class              #27            // java/lang/Integer
   #6 = Fieldref           #7.#28         // com/suninfo/service/test/monitor/ForeachTest.args:[Ljava/lang/Integer;
   #7 = Class              #29            // com/suninfo/service/test/monitor/ForeachTest
   #8 = Class              #30            // java/lang/Object
   #9 = Utf8               integerList
  #10 = Utf8               Ljava/util/List;
  #11 = Utf8               Signature
  #12 = Utf8               Ljava/util/List<Ljava/lang/Integer;>;
  #13 = Utf8               args
  #14 = Utf8               [Ljava/lang/Integer;
  #15 = Utf8               <init>
  #16 = Utf8               ()V
  #17 = Utf8               Code
  #18 = Utf8               LineNumberTable
  #19 = Utf8               foreachTest
  #20 = Utf8               StackMapTable
  #21 = Class              #14            // "[Ljava/lang/Integer;"
  #22 = Utf8               SourceFile
  #23 = Utf8               ForeachTest.java
  #24 = NameAndType        #15:#16        // "<init>":()V
  #25 = Utf8               java/util/ArrayList
  #26 = NameAndType        #9:#10         // integerList:Ljava/util/List;
  #27 = Utf8               java/lang/Integer
  #28 = NameAndType        #13:#14        // args:[Ljava/lang/Integer;
  #29 = Utf8               com/suninfo/service/test/monitor/ForeachTest
  #30 = Utf8               java/lang/Object
{
  java.util.List<java.lang.Integer> integerList;
    descriptor: Ljava/util/List;
    flags:
    Signature: #12                          // Ljava/util/List<Ljava/lang/Integer;>;

  java.lang.Integer[] args;
    descriptor: [Ljava/lang/Integer;
    flags:

  public com.suninfo.service.test.monitor.ForeachTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: new           #2                  // class java/util/ArrayList
         8: dup
         9: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
        12: putfield      #4                  // Field integerList:Ljava/util/List;
        15: aload_0
        16: bipush        12
        18: anewarray     #5                  // class java/lang/Integer
        21: putfield      #6                  // Field args:[Ljava/lang/Integer;
        24: return
      LineNumberTable:
        line 10: 0
        line 11: 4
        line 12: 15

  public void foreachTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=5, args_size=1
         0: aload_0
         1: getfield      #6                  // Field args:[Ljava/lang/Integer;
         4: astore_1
         5: aload_1
         6: arraylength
         7: istore_2
         8: iconst_0
         9: istore_3
        10: iload_3
        11: iload_2
        12: if_icmpge     26
        15: aload_1
        16: iload_3
        17: aaload
        18: astore        4
        20: iinc          3, 1
        23: goto          10
        26: return
      LineNumberTable:
        line 14: 0
        line 17: 26
      StackMapTable: number_of_entries = 2
        frame_type = 254 /* append */
          offset_delta = 10
          locals = [ class "[Ljava/lang/Integer;", int, int ]
        frame_type = 248 /* chop */
          offset_delta = 15
}
SourceFile: "ForeachTest.java"

ok,现在用classpy打开看看,关于classpy环境依赖下载地址上有说明,首先保证你的环境里配置了gradle,然后进入到classpy目录下执行命令:

1.编译:gradle uberjar

2.启动:gradle run

以上两步可以打开classpy界面,顺便手动打开下上面编译的class文件,如下

java字节码分析工具classpy

是不是很清晰,左侧就是标准的字节码总览图,和下面的java字节码总览图对比下:

java字节码分析工具classpy

挺好用的工具,感谢开源世界!


打赏

已有1人打赏

最代码官方的gravatar头像
最近浏览
testjava1122 2019年11月5日
暂无贡献等级
a464216394  LV2 2019年6月6日
ncaihua  LV7 2019年5月17日
zhuce0001 2019年1月29日
暂无贡献等级
Dz______  LV2 2018年8月3日
上世纪风景  LV11 2018年7月16日
依然在路上  LV17 2018年7月9日
JamesOne  LV2 2018年4月19日
wgc_jy  LV21 2018年2月2日
pengboss  LV12 2018年2月2日
顶部 客服 微信二维码 底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友