java自增变量_Java 自增变量

本文通过一个示例代码详细解释了Java中自增变量的使用,包括++i和i++的区别,并通过字节码指令分析了自增操作的执行逻辑。最后,展示了局部变量表和相关指令,帮助理解自增操作的内存和计算过程。
摘要由CSDN通过智能技术生成

Demo

有下面的一道题目,大家猜一下打印结果是什么

public static void main(String[] args) {

int i = 1;

i = i++;

int j = i++;

int k = i + ++i * i++;

System.out.println(i);

System.out.println(j);

System.out.println(k);

}

结果:

4

1

11

讲解

我们先用通俗的说法给个解释,然后再从指令的角度看看他怎么执行。

通俗解法

++i:先自加后使用,也就是遇到这个语句,你脑海里就直接把这块当成已经加了 1的一个变量。

int i = 0;

int x = ++i; // i 先自加,然后再赋值给 xSystem.out.println(x);//1System.out.println(i);//1

i++:先使用后自加

int i = 0;

int x = i++;// i 先赋值给 x,然后自己再自加System.out.println(x);//0System.out.println(i);//1

按照上面给的原则我们来解一下

int i = 1; // i = 1i = i++; // i ++ 先赋值,再自加,但是这里又赋值给了 i,所以相当于没有自加int j = i++; // 先赋值,j = 1,再自加,执行完 i = 2,int k = i + ++i * i++;// 乘除先运算,先算 ++i = 3,再看 i++,因为前面 i= 3,这里就先利用了 3,然后去自加。所以是 2 + 3 * 3System.out.println(i);

System.out.println(j);

System.out.println(k);

有些人可能会迷糊了,其实这个k = i + ++i * i++可以分解为:

i = 2

m = i; // = 2x = ++i; // x = 3,这里没有疑问,y = i++; // y = 3,但是这里为什么=3?因为上一步,我们的加了之后以及是 3 了,这里先利用,所以 y = 3,// 如果你在这里打印 i,应该是 i = 4k = m + x * y;// 2 + 3 * 3 = 11

指令解法

我们寻根问底,为什么会是这个逻辑呢?而且上面的通俗说法总感觉不可靠,我们就来看看底层实现。

使用 idea 编辑器,查看class 的字节码文件【View->Show Bytecode,需要开启插件】

// class version 52.0 (52)

// access flags 0x21

public class top/ybq87/MainClass {

// compiled from: MainClass.java

// access flags 0x1

public ()V

L0

LINENUMBER 12 L0

ALOAD 0

INVOKESPECIAL java/lang/Object. ()V

RETURN

L1

LOCALVARIABLE this Ltop/ybq87/MainClass; L0 L1 0

MAXSTACK = 1

MAXLOCALS = 1

// access flags 0x9

public static main([Ljava/lang/String;)V

L0

LINENUMBER 15 L0

ICONST_1

ISTORE 1

L1

LINENUMBER 16 L1

ILOAD 1

IINC 1 1

ISTORE 1

L2

LINENUMBER 17 L2

ILOAD 1

IINC 1 1

ISTORE 2

L3

LINENUMBER 18 L3

ILOAD 1

IINC 1 1

ILOAD 1

ILOAD 1

IINC 1 1

IMUL

IADD

ISTORE 3

L4

LINENUMBER 19 L4

GETSTATIC java/lang/System.out : Ljava/io/PrintStream;

ILOAD 1

INVOKEVIRTUAL java/io/PrintStream.println (I)V

L5

LINENUMBER 20 L5

GETSTATIC java/lang/System.out : Ljava/io/PrintStream;

ILOAD 2

INVOKEVIRTUAL java/io/PrintStream.println (I)V

L6

LINENUMBER 21 L6

GETSTATIC java/lang/System.out : Ljava/io/PrintStream;

ILOAD 3

INVOKEVIRTUAL java/io/PrintStream.println (I)V

L7

LINENUMBER 22 L7

RETURN

L8

LOCALVARIABLE args [Ljava/lang/String; L0 L8 0

LOCALVARIABLE i I L1 L8 1

LOCALVARIABLE j I L3 L8 2

LOCALVARIABLE k I L4 L8 3

MAXSTACK = 3

MAXLOCALS = 4

}

局部变量表

最底部,我们看到了 4 个局部变量,最后一列是他们的序号,记住这个。

LOCALVARIABLE args [Ljava/lang/String; L0 L8 0

LOCALVARIABLE i I L1 L8 1

LOCALVARIABLE j I L3 L8 2

LOCALVARIABLE k I L4 L8 3

每行代码对应的指令我们看看是什么意思,对照一下 jvm 指令参考表,网上google 下有。

public static void main(String[] args) {

// 注意方法编译之后,产生了 4 个局部变量【LOCALVARIABLE】,args,i,j,k,序号分别为 0,1,2,3 // 我们用数组的概念来代替下,方便理解,arr[0] = args,arr[1] = i,arr[2] = j,arr[3] = k, 当然实际情况更复杂点 // LOAD、STORE 指令后面的参数,第一个参数一般是局部变量的序号,也就是数组角标 /*查看指令ICONST_1 :将 int 型的值 1 推送至栈顶,操作数栈 = 1ISTORE 1 :将栈顶 int 型数值存入指定序号的局部变量,序号为 1 的局部变量为 i,所以 i = 1,操作数栈全部弹出*/

int i = 1;

/*查看指令ILOAD 1 :将指定的 int 型的序号为 1 的局部变量的值,推送至栈顶,也就是将 i 的值压栈,操作数栈:1// iinc 用于实现局部变量的自增操作。在所有字节码指令中,只有该指令可直接用于操作局部变量。// 也就是说,这个命令不会改变操作数栈!IINC 1 1 :int 型的序号为 1 的局部变量,增加指定值 1, 所以 i = 1 + 1,但是操作数栈:1ISTORE 1 :将栈顶 int 型数值存入指定序号的局部变量;序号为 1 的变量为 i,所以将操作数栈顶针,出栈给 i = 1,操作数栈空*/

i = i++;

/*ILOAD 1 :加载序号为 1 的局部变量的值到操作数栈:1IINC 1 1 :局部变量序号为 1 的值+1,也就是局部变量 i 自己+1,i = 2,但是操作数栈还是 1ISTORE 2 :将栈顶的元素弹栈,将值给需要为 2 的局部变量,也就是 j。j = 1,此时 i 已经是 2 了*/

int j = i++;

/*查看指令:ILOAD 1 :序号 = 1 的局部变量值压栈,操作数栈 = 2IINC 1 1 :序号 = 1 的局部变量自加,i 之前已经是 2了,再自加 = 3,操作数栈不变 = 2ILOAD 1 :将 序号 = 1 的局部变量又压栈,也就是 i = 3,将 3 压栈,操作数栈:3,2ILOAD 1 :再压栈,i = 3,操作数栈:3,3,2IINC 1 1 :i++,此时 i = 4,此操作不影响操作数栈,所以操作数栈:3,3,2IMUL :将栈顶两int型数值相乘并将结果压入栈顶,前 2 个值为 3*3 = 9,将 9 压栈,操作数栈为:9,2IADD :将栈顶两int型数值相加并将结果压入栈顶,9 + 2,压栈,操作数栈:11ISTORE 3 :弹栈,赋值给需要为 3 的局部变量,k = 11*/

int k = i + ++i * i++;

// 猜测打印结果 System.out.println(i);

System.out.println(j);

System.out.println(k);

}

这样是不是很清晰了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值