Java i++ 与 ++i 原理

本文目录

前言

1 语句层面

2 计算过程

3 分析原理

4 示例分析


前言

记得大学期间学习C语言的时候,对于 i++ 和 ++i (i-- 和 --i)的理解,一直似懂非懂的状态,因为很多人给出的解释都不够严谨,比如:i++是在操作之后增加,而++i是在操作之前增加。但是,如何确定“操作”的时间点呢?由于平时使用的时候,没有出现过什么问题,为了代码的可读性,也不会刻意写一些“看似很牛X”的复杂且冗长的代码,这个问题也就没有去深究。今天突然心血来潮,想弄清楚其中的原理,并以此文作为记录。

1 语句层面

类似 i += 1 的语句,属于高级语言层面的语句(语法糖),因为,我们可以用另一种代码形式来解释该语句,

例如:i += 1 等同于 i = ( i + 1 )

而 i++ 和 ++i 语句,属于低级语言层面的语句,我们需要从反编译代码中解读其详细的运行机制。

2 计算过程

程序中的变量会存储在主内存中,当需要计算时,主内存中的变量值会被加载到相应的寄存器中,CPU计算过程中,会从寄存器中读取数据,并将计算结果写回寄存器,最终写回主内存。

/**
 * 示例代码
 */
public class demo {

  public void test() {
    int a = 1, b = 2;
    /*
     * 首先,会将 a 和 b 的内存值依次加载至寄存器;
     * 然后,CPU从寄存器中读取两个值并执行相加运算;
     * 接着,将计算结果写回寄存器;
     * 最终,写回 sum 主内存值。 
     */
    int sum = a + b;
  }
}

3 分析原理

通过一个简单的示例程序,根据其反编译内容解读 i++ 和 ++i 的底层操作流程。

/**
 * 示例代码
 */
public class demo {

  public void test1() {
    int i = 0;
    int j = i++;
  }

  public void test2() {
    int i = 0;
    int j = ++i;
  }

  public void test3() {
    int i = 0;
    int j = i++ + i++;
  }
}

通过 javac demo.java 进行编译,得到 demo.class 字节码文件。

再通过 javap -c demo.class 进行反编译,得到反编译代码如下:

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

  public void test1();
    Code:
       0: iconst_0                // 入栈常数0
       1: istore_1                // 赋值1号存储单元为常数0(i = 0)
       2: iload_1                 // 加载1号存储单元值到寄存器(记为stack[0] = 0)
       3: iinc          1, 1      // 递增1号存储单元值(i = i + 1 = 0 + 1 = 1)
       6: istore_2                // 赋值2号存储单元为寄存器值(j = stack[0] = 0)
       7: return                  // 返回(此时:i = 1,j = 0)

  public void test2();
    Code:
       0: iconst_0                // 入栈常数0
       1: istore_1                // 赋值1号存储单元为常数0(i = 0)
       2: iinc          1, 1      // 递增1号存储单元值(i = i + 1 = 0 + 1 = 1)
       5: iload_1                 // 加载1号存储单元值到寄存器(记为stack[0] = 1)
       6: istore_2                // 赋值2号存储单元为寄存器值(j = stack[0] = 1)
       7: return                  // 返回(此时:i = 1,j = 1)

  public void test3();
    Code:
       0: iconst_0                // 入栈常数0
       1: istore_1                // 赋值1号存储单元为常数0(i = 0)
       2: iload_1                 // 加载1号存储单元值到寄存器(记为stack[0] = 0)
       3: iinc          1, 1      // 递增1号存储单元值(i = i + 1 = 0 + 1 = 1)
       6: iload_1                 // 加载1号存储单元值到寄存器(记为stack[1] = 1)
       7: iinc          1, 1      // 递增1号存储单元值(i = i + 1 = 1 + 1 = 2)
      10: iadd                    // 取寄存器值并执行相加操作(stack[0] = stack[0] + stack[1] = 0 + 1 = 1)
      11: istore_2                // 赋值2号存储单元为寄存器值(j = stack[0] = 1)
      12: return                  // 返回(此时:i = 2,j = 1)
}

通过上述反编译内容可知,i++ 和 ++i 操作是在加载 i 值至寄存器步骤的前后执行的,而赋值语句右侧的表达式计算时,是根据加载到寄存器的值进行计算的。

理解了“操作”的时间点,我们便可以理解更复杂的 i++ 和 ++i 相关语句。

但在实际工作中,还是不建议写一些可读性较差的代码(复杂且冗长),不便于后期维护。

4 示例分析

/**
 * 示例代码
 */
public class demo {

  public void test() {
    int i = 0;
    /*
     * ++ -- 操作符本身就具有很高的优先级(仅次于括号),
     * 因此,这里有无括号,结果是一样的,
     * 可化简为:int j = 5 - ++i + ++i;
     */
    int j = 5 - (++i) + (++i);
  }
}

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

  public void test();
    Code:
       0: iconst_0              // 入栈常数0
       1: istore_1              // 赋值1号存储单元为常数0(i = 0)
       2: iconst_5              // 入栈常数5
       3: iinc          1, 1    // 递增1号存储单元值(i = i + 1 = 0 + 1 = 1)
       6: iload_1               // 加载1号存储单元值到寄存器(记为stack[0] = 1)
       7: isub                  // 取寄存器值并执行相减操作(stack[0] = 5 - stack[0] = 5 - 1 = 4)
       8: iinc          1, 1    // 递增1号存储单元值(i = i + 1 = 1 + 1 = 2)
      11: iload_1               // 加载1号存储单元值到寄存器(记为stack[1] = 2)
      12: iadd                  // 取寄存器值并执行相加操作(stack[0] = stack[0] + stack[1] = 4 + 2 = 6)
      13: istore_2              // 赋值2号存储单元为寄存器值(j = stack[0] = 6)
      14: return                // 返回(此时:i = 2,j = 6)
}

  • 26
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值