字节码学习案例


public class MovingAverage {

    private int count = 0;
    private double sum = 0.0D;

    public void submit(double value) {
        this.count++;
        this.sum += value;
    }

    public double getAvg() {
        if (0 == this.count) {
            return sum;
        }

        return this.sum / this.count;
    }
}

public class ForLoopTest {

    private static int[] numbers = {1, 6, 8};

    public static void main(String[] args) {
        MovingAverage ma = new MovingAverage();
        for (int number : numbers) {
            ma.submit(number);
        }
        double avg = ma.getAvg();
    }
}

编译java文件为class

javac -g *.java

反编译ForLoopTest

javap -c -v ForLoopTest

Classfile /F:/lwy/workspace/ByteCode/src/demo/ForLoopTest.class
  Last modified 2021-1-6; size 772 bytes
  MD5 checksum 6fbe54272614cdc3ecee24916f0c9cba
  Compiled from "ForLoopTest.java"
public class demo.ForLoopTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #8.#35         // java/lang/Object."<init>":()V
   #2 = Class              #36            // demo/MovingAverage
   #3 = Methodref          #2.#35         // demo/MovingAverage."<init>":()V
   #4 = Fieldref           #7.#37         // demo/ForLoopTest.numbers:[I
   #5 = Methodref          #2.#38         // demo/MovingAverage.submit:(D)V
   #6 = Methodref          #2.#39         // demo/MovingAverage.getAvg:()D
   #7 = Class              #40            // demo/ForLoopTest
   #8 = Class              #41            // java/lang/Object
   #9 = Utf8               numbers
  #10 = Utf8               [I
  #11 = Utf8               <init>
  #12 = Utf8               ()V
  #13 = Utf8               Code
  #14 = Utf8               LineNumberTable
  #15 = Utf8               LocalVariableTable
  #16 = Utf8               this
  #17 = Utf8               Ldemo/ForLoopTest;
  #18 = Utf8               main
  #19 = Utf8               ([Ljava/lang/String;)V
  #20 = Utf8               number
  #21 = Utf8               I
  #22 = Utf8               args
  #23 = Utf8               [Ljava/lang/String;
  #24 = Utf8               ma
  #25 = Utf8               Ldemo/MovingAverage;
  #26 = Utf8               avg
  #27 = Utf8               D
  #28 = Utf8               StackMapTable
  #29 = Class              #23            // "[Ljava/lang/String;"
  #30 = Class              #36            // demo/MovingAverage
  #31 = Class              #10            // "[I"
  #32 = Utf8               <clinit>
  #33 = Utf8               SourceFile
  #34 = Utf8               ForLoopTest.java
  #35 = NameAndType        #11:#12        // "<init>":()V
  #36 = Utf8               demo/MovingAverage
  #37 = NameAndType        #9:#10         // numbers:[I
  #38 = NameAndType        #42:#43        // submit:(D)V
  #39 = NameAndType        #44:#45        // getAvg:()D
  #40 = Utf8               demo/ForLoopTest
  #41 = Utf8               java/lang/Object
  #42 = Utf8               submit
  #43 = Utf8               (D)V
  #44 = Utf8               getAvg
  #45 = Utf8               ()D
{
  public demo.ForLoopTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>
":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Ldemo/ForLoopTest;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=6, args_size=1
         0: new           #2                  // class demo/MovingAverage
         3: dup
         4: invokespecial #3                  // Method demo/MovingAverage."<ini
t>":()V
         7: astore_1
         8: getstatic     #4                  // Field numbers:[I
        11: astore_2
        12: aload_2
        13: arraylength
        14: istore_3
        15: iconst_0
        16: istore        4
        18: iload         4
        20: iload_3
        21: if_icmpge     43
        24: aload_2
        25: iload         4
        27: iaload
        28: istore        5
        30: aload_1
        31: iload         5
        33: i2d
        34: invokevirtual #5                  // Method demo/MovingAverage.submi
t:(D)V
        37: iinc          4, 1
        40: goto          18
        43: aload_1
        44: invokevirtual #6                  // Method demo/MovingAverage.getAv
g:()D
        47: dstore_2
        48: return
      LineNumberTable:
        line 8: 0
        line 9: 8
        line 10: 30
        line 9: 37
        line 12: 43
        line 13: 48
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
           30       7     5 number   I
            0      49     0  args   [Ljava/lang/String;
            8      41     1    ma   Ldemo/MovingAverage;
           48       1     2   avg   D
      StackMapTable: number_of_entries = 2
        frame_type = 255 /* full_frame */
          offset_delta = 18
          locals = [ class "[Ljava/lang/String;", class demo/MovingAverage, clas
s "[I", int, int ]
          stack = []
        frame_type = 248 /* chop */
          offset_delta = 24

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=4, locals=0, args_size=0
         0: iconst_3
         1: newarray       int
         3: dup
         4: iconst_0
         5: iconst_1
         6: iastore
         7: dup
         8: iconst_1
         9: bipush        6
        11: iastore
        12: dup
        13: iconst_2
        14: bipush        8
        16: iastore
        17: putstatic     #4                  // Field numbers:[I
        20: return
      LineNumberTable:
        line 5: 0
}
SourceFile: "ForLoopTest.java"

反编译解读:MovingAverage ma = new MovingAverage();

new #2为创建MoveingAverage对象

dup则复制操作数栈顶的值

invokespecial #3则为执行#3所对应的函数为MoveingAverage的init构造函数

astore_1则表示将栈顶元素的引用赋值给LocalVariableTable中slot是1变量ma

getstatic #4则表示获取指定类的静态域,并将其值压入栈顶---实则是number的引用

astore_2则将栈顶引用型数值存入第2个本地变量

aload_2则表示将第2个引用类型本地变量推送至栈顶

arraylength获得数组的长度值并压入栈顶

istore_3将栈顶int型数值存入第3个本地变量

iconst_0将int型0推送至栈顶

istore 4将栈顶int型数值存入指定本地变量

iload 4将指定的int型本地变量推送至栈顶(18行

iload_3将第3个int型本地变量推送至栈顶

if_icmpge 43比较栈顶两int型数值大小,当结果大于等于0时跳转到多少行

aload_2将第2个引用类型本地变量推送至栈顶

iload 4将指定的int型本地变量推送至栈顶

iaload将int型数组指定索引的值推送至栈顶(将索引4中值所对应的值压到栈顶)

istore 5将栈顶int型数值存入指定本地变量(把【1,6,8】6赋值给第5个本地变量)

aload_1将第1个引用类型本地变量推送至栈顶(把ma压栈)

iload 5将指定的int型本地变量推送至栈顶(把6压栈)

i2d将栈顶int型数值强制转换成double型数值并将结果压入栈顶(把6出栈,后转换成double后压栈)

invokevirtual #5调用实例方法(执行ma.submit(6)方法)

iinc 4,1将指定int型变量增加指定值,可以有两个变量,分别表示index, const,index指第index个int型本地变量,const增加的值(第4个本地变量的值+1,也就是索引值+1)

goto 18无条件跳转18行

以上利用本地的第二个、第三个、第四个变量进行记录数组、数组长度、及当前索引值

aload_1把ma压栈

invokevirtual #6执行ma.getAvg()函数返回值在栈顶

dstore_2将栈顶double型数值存入第2个本地变量avg

return函数结束

猜你喜欢

转载自blog.csdn.net/HashMap_Set/article/details/112284600
今日推荐