【Java】深入理解i++、++i

先看两个例子

示例一

public class Test {
    public static void main(String[] args) {
        int i = 0;
        int j = i++;

        System.out.println("i=" + i);
        System.out.println("j=" + j);
    }
}

示例二 

public class Test {
    public static void main(String[] args) {
        int i = 0;
        i = i++;
        int j = i++;

        System.out.println("i=" + i);
        System.out.println("j=" + j);
    }
}

结果都是

i=1
j=0

怎么解释?我猜你会说:“i先赋值给j,再自增”

额。。。可以这么理解,但代码在实际执行过程中不是这样的。因为在运算符优先级中,++优先于=,所以++会先运行,赋值后运行。

知识储备

这里简单说明,详细解释可网上查阅

1、运算符优先级:++优先于=,所以++会先运行,赋值后运行。

2、Java虚拟机的栈帧

        局部变量表:用于存放临时变量,++是在这里面操作的

        操作数栈:先进后出,用于数据操作,如加、减、乘与除的计算等等

        动态链接:本文用不到,无视

        方法返回地址:本文用不到,无视

3、Java虚拟机字节码指令

iconst_<i>:将数据<i>压入【操作数栈】,这里的i是数值

注:

iconst_<i>:i的取值范围是[-1,5]

bipush:[-128,127]

sipush:[-32768,32767]

ldc :[-2147483648,2147483647]

istore_<i>:将【操作数栈】栈顶的数据弹出(弹出后,栈里没有了),并存到【局部变量表】的<i>位置

注:静态变量i从0开始,非静态从1开始,所以后面代码里看到的是1开始的

iload_<i>:将【局部变量表】的<i>位置的数据,加载压入到【操作数栈】

iinc          <i>, <j>:将【局部变量表】的<i>位置的数据,加上<j> 

注:iinc时,【操作数栈】没有变化

下面进入正题

先用jdk自带的工具把【示例一代码】反编译成字节码。

获取class文件

javac Test.java

反汇编,得到字节码

javap -c Test.class

得到字节码代码 

public class com.test.Test {
  public com.test.Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: iinc          1, 1
       6: istore_2
       7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      10: new           #3                  // class java/lang/StringBuilder
      13: dup
      14: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      17: ldc           #5                  // String i=
      19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: iload_1
      23: invokevirtual #7                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      26: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      29: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      32: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      35: new           #3                  // class java/lang/StringBuilder
      38: dup
      39: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      42: ldc           #10                 // String j=
      44: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      47: iload_2
      48: invokevirtual #7                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      51: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      54: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      57: return
}

解读前5行

0: iconst_0                》》常量0入【操作数栈】
1: istore_1                 》》将【操作数栈】栈顶的数据弹出,并存到【局部变量表】1的位置,此时i=0
2: iload_1                  》》将【局部变量表】1位置的数据,压入【操作数栈】,此时,栈顶数据是0
3: iinc          1, 1        》》将【局部变量表】1位置的数据,加1,此时i=1
6: istore_2                》》将【操作数栈】栈顶的数据弹出,并存到【局部变量表】2的位置,此时j=0

图解

示例二的字节码代码

public class com.test.Test {
  public com.test.Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: iinc          1, 1
       6: istore_1
       7: iload_1
       8: iinc          1, 1
      11: istore_2
      12: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      15: new           #3                  // class java/lang/StringBuilder
      18: dup
      19: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      22: ldc           #5                  // String i=
      24: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      27: iload_1
      28: invokevirtual #7                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      31: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      34: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      37: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      40: new           #3                  // class java/lang/StringBuilder
      43: dup
      44: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      47: ldc           #10                 // String j=
      49: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      52: iload_2
      53: invokevirtual #7                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      56: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      59: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      62: return
}

 直接上图解

再来个++i的示例

源码

public class Test {
    public static void main(String[] args) {
        int i = 0;
        int j = ++i;

        System.out.println("i=" + i);
        System.out.println("j=" + j);
    }
}

字节码

public class com.test.Test {
  public com.test.Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: iinc          1, 1
       5: iload_1
       6: istore_2
       7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      10: new           #3                  // class java/lang/StringBuilder
      13: dup
      14: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      17: ldc           #5                  // String i=
      19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: iload_1
      23: invokevirtual #7                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      26: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      29: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      32: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      35: new           #3                  // class java/lang/StringBuilder
      38: dup
      39: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      42: ldc           #10                 // String j=
      44: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      47: iload_2
      48: invokevirtual #7                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      51: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      54: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      57: return
}

解读

0: iconst_0                》》常量0入【操作数栈】
1: istore_1                》》将【操作数栈】栈顶的数据弹出,并存到【局部变量表】1的位置,此时i=0
2: iinc          1, 1        》》将【局部变量表】1位置的数据,加1,此时i=1
5: iload_1                》》将【局部变量表】1位置的数据,压入【操作数栈】,此时,栈顶数据是1
6: istore_2                》》将【操作数栈】栈顶的数据弹出,并存到【局部变量表】2的位置,此时j=1

图解

 

 运行结果

i=1
j=1

 希望对你有所帮助!

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值