Demo 如下所示
public static void main(String[] args) {
System.out.println(Demo.method1(10));
System.out.println(Demo.method2(10));
}
public static int method1(int a) {return a++;}
public static int method2(int b) {return ++b;}
运行结果:
10
11
Process finished with exit code 0
我们通过反编译得到字节码进行分析,看到method1
方法的字节码如下所示
0 iload_0
1 iinc 0 by 1
4 ireturn
为什么 a++ 之后还是返回a值呢?
iload_0
表示的是从栈中局部变量
表获取10,然后把10压入操作数栈
,这个时候操作数栈
中有一个值就是10,然后执行iinc 0 by 1
表示在把局部变量表
中索引为0的位置值也就是我们的10, 进行加1,这个时候局部变量表
中的值其实就变成了了11了,然后执行ireturn
,ireturn
作用是把我们在操作数栈
的值或者是地址引用给出栈,这里因为我们上述的iload_0
把10压入了我们的操作数栈
中,所以我们的ireturn
就是把我们的10弹出栈了,至此给我们System.out.println(method1(10))
输出的就是10了
这里我们需要明白局部变量表和操作数栈有什么作用,大致的说下:
局部变量
: 故名只意,就是用来存储我们的基本类型局部变量的值,或者是存储我们的引用类型的地址引用操作数栈
:方法执行和字节码指令的执行,会从局部变量表或对象实例的字段中复制常量或变量写入到操作数栈,再随着计算的进行将栈中元素出栈到局部变量表或者返回给方法调用者,也就是出栈/入栈操作。一个完整的方法执行期间往往包含多个这样出栈/入栈的过程。
这里涉及到的机器操作指令有兴趣的可以看看这个文档,google翻译即可查看指令
好了,说完了method1
方法之后,应该就知道为什么a++是返回的本身了吧,其实是相当于返回了一个副本缓存
接着我们再看看method2
方法字节码如下所示:
0 iinc 0 by 1
3 iload_0
4 ireturn
为什么这个++a返回的是a+1的值呢?
我们先看看System.out.println(method2(10));
这句代码中把10传递给了method2(int a)
方法,这个时候因为我们的int a是一个局部变量,所以method2
方法中的a会存在索引为0的局部变量表
中,值也就是传递过来的10,接着执行指令iinc 0 by 1
,就是把局部变量表
索引为0的值給加1,变成了11
紧接着执行iload_0
指令,作用是把局部变量表
索引为0的值给我压入操作数栈
中,因为这个时候索引为0的局部变量
值已经是11了,所以压入操作数栈
中就值就是11,然后通过ireturn指令
又把这个11給我弹出操作数栈
了,返回给我们的System.out.prinntln()
调用者了,所以输出的就是11啦
如果还是不太清楚的话,可能还是对这几个指令不熟悉而已,建议把这几个指令看明白就行了