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

发布时间:2023年12月20日

先看两个例子

示例一

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

?希望对你有所帮助!

文章来源:https://blog.csdn.net/zxcyxg123/article/details/135065880
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。