
关于Java4种自增方法的不同
4种自增的方法
- i++
- ++i
- i+=1
- i=i+1
示例代码
1 | public class HelloWorld{ |
运行结果
1 | 1 |
解释说明
- 第一种
i=i+1:首先=的优先级小于+,所以该表达式会首先进行加法操作,然后再进行赋值操作 - 第二种
i+=1:第一种方法的优化版本?; - 第三种
i++:先参与操作,后自增 - 第四种
++i:先自增,后参与操作
以上都是大家都熟知的想法
从字节码的角度
1 | Compiled from "HelloWorld.java" |
| 指令码 | 操作码(助记符) | 操作数 | 描述(栈指操作数栈) |
|---|---|---|---|
| 0x03 | iconst_0 | 无 | 0(int)值入栈 |
| 0x04 | iconst_1 | 无 | 1(int)值入栈 |
| 0x1a | iload_0 | 无 | 从局部变量0中装载int类型值入栈 |
| 0x3b | istore_0 | 无 | 将栈顶int类型值保存到局部变量0中 |
| 0x60 | iadd | 无 | 将栈顶两int类型数相加,结果入栈 |
| 0xb2 | getstatic | indexbyte1 indexbyte2 | 获取静态字段的值 |
| 0x84 | iinc | indexbyte constbyte | 将整数值constbyte加到indexbyte指定的int类型的局部变量中 |
| 0xb8 | invokestatic | indexbyte1 indexbyte2 | 调用静态方法 |
| 0xb6 | invokevirtual | indexbyte1 indexbyte2 | 运行时方法绑定调用方法 |
method1
解释一下操作符:
- 将常量0压入操作数栈
- 将栈顶的int类型的数保存到局部变量表的第0个索引的位置
- 从局部变量表的第0个索引的位置,将整数压入栈中
- 将常量1压入操作数栈
- 将栈顶的两个int类型数相加,将结果1压入操作数栈
- 将结果1存储到局部变量的第0个索引的位置
- 获取静态字段PrintStream的值
- 将局部变量表第0个索引位置的值压入栈
- 调用实例方法print输出结果
- 方法结束返回
method2 method3 method4
我们可以看到剩下的三个方法的操作码是一致的,唯一不同的是操作码的执行顺序。而且多了一个新指令,该指令之后带有2个数值,分别是0和1,第一个参数是局部变量表的索引值,也就是说局部变量表第0索引处存放着一个int类型的值,第二个参数就是自增的大小,将索引0处的int值加1,得到结果。注意,这个操作是在局部变量表上操作的,而不是在操作数栈上。
这时候我们看一下i++和++i的操作码,i++是先将局部变量表0处的值载入到操作数栈,然后才将局部变量表0处的值加1,接下来调用方法print的时候输出的是操作数栈的值,此时值为0,所以最终输出的结果就如我们所知一致,输出0。
++i的话就正好与i++相反先加1,然后将值载入操作数栈,再调用print方法输出,得到的结果当然是1。
总结
其实,但从操作码来看,无论是i++还是++i还是i+=1的操作码的个数都是比i=i+1少的,这样是不是可以说,前者的运行效率会高于后者呢?
- Title: 关于Java4种自增方法的不同
- Author: 三页半
- Created at : 2018-10-10 00:00:00
- Updated at : 2024-08-14 14:54:39
- Link: https://smallclover.github.io/2018/10/10/2018-10-10-Java自增方法的解析/
- License: This work is licensed under CC BY-NC-SA 4.0.
Comments