Java ++i 与 i++ 底层原理

发布于:2025-08-04 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、概念解释

1.1 指令含义

  • ICONST_x :将常量x压到操作数栈中
  • ISTORE_x :将操作数栈顶元素写入到本地变量表第x+1位置
  • IINC m n :将本地变量表中第m+1位置进行加n操作
  • LINENUMBER :这个就是标注我们的行号
  • ILOAD_x :将局部变量表第x+1位置元素加入操作数栈中,和ISTORE相反

1.2 局部变量表

  • 是一个数组,用于存储方法中所有的局部变量,包括:
    • 方法参数
    • 方法内部定义的局部变量(int、Object、boolean 等)
    • 编译器临时变量(如:中间值、i++的旧值)
  • 每个变量占用 1 或 2 个槽(slot)
    • int, float, reference → 占1个槽位
    • long, double → 占2个槽位
示例:
public int add(int a, int b) {
    int c = a + b;
    return c;
}

这个方法的局部变量表可能如下:

槽位

内容

0

this(对象引用)

1

a

2

b

3

c

1.3 操作数栈

  • 是一个后进先出(LIFO)栈,用于临时存放操作数、计算中间结果
  • 所有字节码指令操作的“数据”,都要先从局部变量表加载进栈,再在栈中操作
  • 每个方法调用都会创建一个新的栈帧,包含一个新的操作数栈
示例:
int a = 3;
int b = 4;
int c = a + b;

字节码执行过程(假设槽位1=3,槽位2=4):

iload_1       // 操作数栈: 3
iload_2       // 操作数栈: 3, 4
iadd          // 操作数栈: 7
istore_3      // 局部变量槽3 = 7

二、简单示例

public class Test {
    public static void main(String[] args) {
        int i = 1;
        int a = i++; // 后缀递增
        int b = ++i; // 前缀递增
    }
}

通过Javap 反编译字节码:

javac Test.java
javap -c Test

输出(关键部分)如下:

0: iconst_1         // 将常量1压入栈
1: istore_1         // i = 1

2: iload_1          // 将i的值加载进操作数栈(i = 1)
3: iinc 1, 1        // i = i + 1,此时 i = 2
6: istore_2         // 把栈顶旧值(1)赋值给 a
//结果 a = 1,i = 2

7: iinc 1, 1        // i = i + 1,此时 i = 3
10: iload_1         // 把新值加载进栈(i = 3)
11: istore_3        // b = 3
//结果 b = 3,i = 3

分析区别:

表达式

步骤

字节码行为

结果

a = i++

先取值后自增

iload_1(先把i原值放进操作数栈)

iinc(i加1,此时 i = 2)

istore_2(把栈顶旧值赋值给 a)

a = 1,i = 2

b = ++i

先自增后取值

iinc(i先加1,此时 i = 3)

iload_1(把新值加载进栈)

istore_3(把栈顶值赋给b)

b = 3,i = 3

三、深入示例

示例代码:

public class Test {
    public static void main(String[] args) {
        int i = 1;
        int a = i++ + i++;  // 表达式1
        int b = i++ + ++i;  // 表达式2

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}

 编译并反编译(javac Test.java + javap -c Test):

 0: iconst_1         // i = 1
 1: istore_1

 2: iload_1          // 把 i=1 压入栈顶 → 用于 i++ 的结果
 3: iinc 1, 1        // i++:i 变为 2
 6: iload_1          // 把 i=2 压入栈顶 → 第二次 i++
 7: iinc 1, 1        // i++:i 变为 3
10: iadd             // 1 + 2
11: istore_2         // a = 3

12: iload_1          // i=3,压栈(用于 i++ 的结果)
13: iinc 1, 1        // i++:i = 4
16: iinc 1, 1        // ++i:i = 5
19: iload_1          // i=5,再压栈
20: iadd             // 3 + 5
21: istore_3         // b = 8

3.1 表达式 1:int a = i++ + i++

初始:i = 1
  1. iload_1 → 把 i 的当前值 1 压入操作数栈(用于加法的左值
  2. iinc 1, 1 → i 自增为 2
  3. iload_1 → 把 i 的当前值 2 压入操作数栈(用于加法的右值
  4. iinc 1, 1 → i 自增为 3
  5. iadd → 1 + 2 = 3
  6. istore_2 → 存入变量 a
最终结果:
  • i = 3
  • a = 3
int a = i++ + i++ 的操作数栈变化示意图:

步骤

i 值

操作数栈

说明

初始

1

iload_1

1

1

压入 i(用于计算)

iinc

2

1

i++

iload_1

2

1, 2

再压入 i(计算)

iinc

3

1, 2

i++

iadd

3

3

1 + 2

istore_2

3

a = 3

3.2 表达式 2:int b = i++ + ++i

此时 i = 3
  1. iload_1 → 压入 i 的当前值 3(用于 i++)
  2. iinc 1, 1 → i++,i 变为 4
  3. iinc 1, 1 → ++i,i 再变为 5
  4. iload_1 → 压入 i 的当前值 5(用于 ++i)
  5. iadd → 3 + 5 = 8
  6. istore_3 → 存入变量 b
最终结果:
  • i = 5
  • b = 8
int b = i++ + ++i 的操作数栈变化示意图:

步骤

i 值

操作数栈

说明

初始

3

iload_1

3

3

i++ 左值

iinc

4

3

i++

iinc

5

3

++i

iload_1

5

3, 5

++i 右值

iadd

5

8

3 + 5

istore_3

5

b = 8


网站公告

今日签到

点亮在社区的每一天
去签到