天天看點

通過位元組碼了解i++和++i的差別

/**
 * 從位元組碼角度分析 a++  相關題目
 */
public class Demo3_12_3 {
    public static void main(String[] args) {
        int a = 10;
        int b = a++;
    }
}
           

生成的位元組碼

Classfile /F:/BaiduNetdiskDownload/JVM/2019-解密JVM資料/代碼/jvm/out/production/jvm/cn/itcast/jvm/t3/bytecode/Demo3_12_3.class
  Last modified 2021-2-28; size 473 bytes
  MD5 checksum 924e6b2ead1874ed36a1757db8fc4ecd
  Compiled from "Demo3_12_3.java"
public class cn.itcast.jvm.t3.bytecode.Demo3_12_3
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#20         // java/lang/Object."<init>":()V
   #2 = Class              #21            // cn/itcast/jvm/t3/bytecode/Demo3_12_3
   #3 = Class              #22            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               LocalVariableTable
   #9 = Utf8               this
  #10 = Utf8               Lcn/itcast/jvm/t3/bytecode/Demo3_12_3;
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               args
  #14 = Utf8               [Ljava/lang/String;
  #15 = Utf8               a
  #16 = Utf8               I
  #17 = Utf8               b
  #18 = Utf8               SourceFile
  #19 = Utf8               Demo3_12_3.java
  #20 = NameAndType        #4:#5          // "<init>":()V
  #21 = Utf8               cn/itcast/jvm/t3/bytecode/Demo3_12_3
  #22 = Utf8               java/lang/Object
{
  public cn.itcast.jvm.t3.bytecode.Demo3_12_3();
    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 6: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcn/itcast/jvm/t3/bytecode/Demo3_12_3;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=3, args_size=1
         0: bipush        10  //把10壓入操作數棧中
         2: istore_1	//把10(操作數棧頂資料)存儲在局部變量表的1号位上
         3: iload_1		//把局部變量表1号位上的資料壓到操作數棧中,但是局部變量表還是會保留住資料并不會因為壓到操作數棧之後資料就沒有了
         4: iinc          1, 1	//此時進行++操作,因為這個++操作是在局部變量表中進行的,是以此時局部變量表上的資料為11,但是操作數棧中的資料為10
         7: istore_2
         8: return
      LineNumberTable:
        line 8: 0
        line 9: 3
        line 10: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;
            3       6     1     a   I
            8       1     2     b   I
}
SourceFile: "Demo3_12_3.java"
           
/**
 * 從位元組碼角度分析 a++  相關題目
 */
public class Demo3_12_4 {
    public static void main(String[] args) {
        int a = 10;
        int b = ++a;
    }
}
           

生成的位元組碼

Classfile /F:/BaiduNetdiskDownload/JVM/2019-解密JVM資料/代碼/jvm/out/production/jvm/cn/itcast/jvm/t3/bytecode/Demo3_12_4.class
  Last modified 2021-2-28; size 473 bytes
  MD5 checksum eba48d8bd84e156b984607b002110fc6
  Compiled from "Demo3_12_4.java"
public class cn.itcast.jvm.t3.bytecode.Demo3_12_4
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#20         // java/lang/Object."<init>":()V
   #2 = Class              #21            // cn/itcast/jvm/t3/bytecode/Demo3_12_4
   #3 = Class              #22            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               LocalVariableTable
   #9 = Utf8               this
  #10 = Utf8               Lcn/itcast/jvm/t3/bytecode/Demo3_12_4;
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               args
  #14 = Utf8               [Ljava/lang/String;
  #15 = Utf8               a
  #16 = Utf8               I
  #17 = Utf8               b
  #18 = Utf8               SourceFile
  #19 = Utf8               Demo3_12_4.java
  #20 = NameAndType        #4:#5          // "<init>":()V
  #21 = Utf8               cn/itcast/jvm/t3/bytecode/Demo3_12_4
  #22 = Utf8               java/lang/Object
{
  public cn.itcast.jvm.t3.bytecode.Demo3_12_4();
    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 6: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcn/itcast/jvm/t3/bytecode/Demo3_12_4;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=3, args_size=1
         0: bipush        10
         2: istore_1
         3: iinc          1, 1
         6: iload_1
         7: istore_2
         8: return
      LineNumberTable:
        line 8: 0
        line 9: 3
        line 10: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;
            3       6     1     a   I
            8       1     2     b   I
}
SourceFile: "Demo3_12_4.java"
           

其實 i++ 和 ++i 的差別就在 iinc 和 iload_1 的先後順序。

如果在後面都加上System.out.println(a);

這個時候就會增加點位元組碼

8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_1	//這裡其實又重新把局部變量表上的 11 壓倒操作數棧中,此時a的值就會變成11
12: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
           
public static void main(String[] args) {
        int i = 0;
        int x = 0;
        while (i < 10) {
            x = x++; // 因為這個x++ 會先執行iload,把操作數棧上的值0重新放到本地變量表中,導緻x的值一直為0
            i++;
        }
        System.out.println(x); // 結果是 0 
    }