自增与自减的机制——为什么 int i = 0; i = i++; i 的结果为0?

本文详细探讨了Java中自增自减操作符的工作原理,通过JVM字节码指令分析了i = i++的结果为0的原因。解释了在自增操作中,局部变量表的值被更新,但操作数栈中的值并未改变,导致最终赋值时覆盖了自增的结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.问题

Java 中运行以下代码 :

public static int test() {
		int i = 0;
		i = i++;
		return i;
}

返回结果为:0

2.JVM执行的代码

直接在Windows命令窗口中使用 javap -c XXX 查看JVM执行的代码:

public static int test();
  Code:
     0: iconst_0
     1: istore_0
     2: iload_0
     3: iinc          0, 1
     6: istore_0
     7: iload_0
     8: ireturn

JVM调用执行该方法时,对应栈帧(Stack Frame) 在虚拟机中入栈;栈帧中包含:局部变量表、操作数栈、动态链接、方法返回地址等信息。

局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量,i就放在局部变量表中;而操作数栈是一个后入先出的栈,用于方法的计算。

3.现在来看看JVM的字节码指令

  • 0: iconst_0 --> 将int类型的0入栈,即放到操作数栈的栈顶
  • 1: istore_0 --> 将操作数栈顶元素 0 弹出,存入局部变量表的0号索引位上(这是个静态方法,第0位不用存放当前对象的引用)
  • 2: iload_0 --> 将局部变量表的0号索引位的值的副本,压入操作数栈
  • 3: iinc 0, 1 --> iinc是对int类型的值进行自增操作:0代表局部变量表索引;1代表要增的数值; —即,局部变量表中 0 号位置的数值+1 变为 1
  • 6: istore_0 --> 将操作数栈顶元素 0 弹出,存储到局部变量表的索引 0 位;此时覆盖了上一步局部变量表的自增计算结果
  • 7: iload_0 --> 将局部变量表的0号索引位的值的副本,压入操作数栈
  • 8: ireturn --> 从当前方法返回int

4.结论

自增操作是对局部变量表中的值进行自增,而操作数栈中的值并不会改变。

当 i = i++ 进行赋值操作时,先会将局部变量表中的i值(0)押入操作数栈,然后自增(局部变量表中 -> 1)(操作数栈顶的值并没有发生变化),最后将操作数栈顶的元素弹出并覆盖局部变量表中的数值。

5.扩展

i = ++i:

public static int test() {
	int i = 0;
	i = ++i;
	return i;
}

返回值:1

JVM的字节码指令:

public static int test();
   Code:
      0: iconst_0
      1: istore_0
      2: iinc          0, 1
      5: iload_0
      6: istore_0
      7: iload_0
      8: ireturn

区别:

第2、3步执行顺序不一样,也就是i=++i先自增,后入栈,前后值一致。

那 i 如果是类的静态变量呢?

//i = i++
static int i =0;
public static int test() {
	i = i++;
	return i;
}

//i = ++i
static int i =0;
public static int test() {
	i = ++i;
	return i;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值