详讲 i = i ++和 i=++ i 的区别(从字节码的角度解析)

java代码如下

public class test {
    public static void main(String[] args) {
        int i=1;
        i=i++;
        System.out.println(i);

        int j=1;
        j=++j;
        System.out.println(j);
    }
}

先提出问题,此时读者认为最后输出的值是什么呢?

我们先不进行解答,先展示一下class反编译之后的文件

public class test {
    public test() {
    }

    public static void main(String[] args) {
        int i = 1;
        int i = i++;
        System.out.println(i);
        int j = 1;
        ++j;
        System.out.println(j);
    }
}

我们可以看到原来的i=i++;操作被替换成了int i=i++;,而j=++j;被替换成了++j;,目前我们根据class文件发现了i=i++和j=++j的直接区别,下面我们将根据字节码进行解释。

main方法的字节码如下(建议文章后续操作都要根据此字节码进行观看)

 0 iconst_1
 1 istore_1
 2 iload_1
 3 iinc 1 by 1
 6 istore_1
 7 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
10 iload_1
11 invokevirtual #3 <java/io/PrintStream.println : (I)V>

--------上面的是i的操作,下面的是j的操作----------

14 iconst_1
15 istore_2
16 iinc 2 by 1
19 iload_2
20 istore_2
21 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
24 iload_2
25 invokevirtual #3 <java/io/PrintStream.println : (I)V>
28 return

我们根据字节码一步一步来解释

前提条件当前局部变量表为

局部变量表
序号012 
元素thisij 
 00 

 

操作数栈(还是空的)

操作数栈
 
 
 
 

 i 值操作过程

1、操作1:iconst_1:将操作数栈放一个int值为1

2、操作2:istore_1:将操作数栈出栈操作,赋值给局部变量表序号为1的元素i,这两部操作相当于我们写的int i=1;操作,如图所示:

 

3、操作3:iload_1:注意此时和++j的操作不一样了,iload_1表示将局部变量表序号为1的元素值执行入栈操作,将值放到操作数栈。

 

 

4、操作4:iinc 1 by 1:表示局部变量表序号1的元素自增加1操作,此时i值为2,具体如图所示:

 5、操作5: istore_1:和操作2一样为出栈操作,将操作数栈的值赋给局部变量表序号为1的元素,也就是说 i 值得变化是从0(初始值)-1-2-1的过程最后为1。如图所示

 i之后的操作就是输出,不过多解释了

j 值操作过程

1、操作1、2: iconst_1  istore_2:和 i 操作1、2一致,就是int j = 1 ;的过程

2、操作3:iinc 2 by 1:注意此时我们和 i 从操作不一样,这时我们是先进行自增操作,也就是说当前局部变量表的 j 值为2了

3、操作4、5:此时我们再次将局部变量表序号为2的元素值放到操作数栈,然后为 j 进行赋值,操作如图

 

 

 最后 i 的值为1,而 j 的值为2

题外话:

有趣的是如果我们不进行输出的操作,无论是 i = i++,还是 j = ++j 都会被class反编译成++i / j,但是在字节码角度上来看又完全不同

public class test {
    public static void main(String[] args) {
        int i=1;
        i=i++;

        int j=1;
        j=++j;
    }
}

class反编译后的文件

public class test {
    public test() {
    }

    public static void main(String[] args) {
        int i = 1;
        ++i;
        int j = 1;
        ++j;
    }
}

查看这个反编译后的文件,我们竟无法直接查看出  i = i++、 j = ++j 的直接区别,所以贴一下字节码

 0 iconst_1
 1 istore_1
 2 iload_1
 3 iinc 1 by 1
 6 istore_1
 7 iconst_1
 8 istore_2
 9 iinc 2 by 1
12 iload_2
13 istore_2
14 return

在字节码角度来看又有很大的区别,读者可以根据上述的知识自己解析一下~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值