1. i++和++i的基本概念
在几乎所有的命令式编程语言中,必然都会有 i++ 和 ++i 这种语法。有些语言中 i++ 和 ++i 既可以作为左值又可以作为右值,笔者专门测试了一下,在 Java 语言中,这两条语句都只能作为右值,而不能作为左值。同时,它们都可以作为独立的一条指令执行。
关于 i++ 和 ++i 的区别,稍微有经验的程序员都或多或少都是了解的,为了文章的完整性,本文也通过实例来简单地解释一下。
案例 1:
运行结果:
案例 2:
运行结果:
上面的例子中可以看到,无论是 i++ 和 ++i 指令,对于 i 变量本身来说是没有任何区别的,指令执行的结果都是 i 变量的值加 1。而对于 j 来说前 ++ 和后 ++ 结果却不一样了。
2. i++ 和 ++i 的实现原理
接下来让我们深入到编译后的字节码层面上来了解 i++ 和 ++i 的实现原理,为了方便对比,将这两个指令分别放在 2 个不同的方法中执行,源代码如下:
将上面的源代码编译之后,使用 javap 命令查看编译生成的代码(忽略次要代码)如下:
可以从上面的字节码文件看出,造成结果不同的原因就是:“1 号存储单元的值加 1 的操作”和“将 1 号存储单元的值加载到数据栈”的先后顺序造成的。如果前者在后者之前,则结果就是 1,反之则为 0。
3. i++ 和 ++i 使用的一些坑
i++ 和 ++i 在一些特殊场景下可能会产生意想不到的结果,本节介绍两种会导致结果混乱的使用场景,并剖析其原因。
01
案例1:i=i++导致的结果异常
运行结果:
正常来讲,执行的结果应该是:i = 1,实际结果却是:i = 0,这多少会让人有些诧异。为什么会出现这种情况呢?我们来从编码后的代码中找答案。上面的代码编译后的核心代码如下:
从编码指令可以看出,i 被栈顶值所覆盖,导致最终 i 的值仍然是 i 的初始值。无论重复多少次 i = i++ 操作,最终 i 的值都是其初始值。
实际上:i++ 有中间缓存变量,,i = i++ 等价于:
所以 i 不变, 依然是0。
02
案例2
运行结果:
和上面上面的两端代码中唯一的差别就是 i++ 的结果有没有赋值给 i ,但是输出的 i 的结果一个加了1,而1个没有加。这是为什么呢?我们看下编译的字节码文件:
-------- END ---------