这个问题的完整语义是:
Java方法调用时,参数变量是值传递还是引用传递的。
所谓引用传递是指传递栈帧中的局部变量表的变量槽地址,值传递是指传递栈帧中的局部变量表的变量槽地址所存储的值。
局部变量表中的变量槽分为两种:
基本类型变量槽会直接存储字面量值,引用类型变量槽会存储堆中的对象地址。
回答这个问题,最有说服力的角度还是从jvm来解释,来看下面这个Java代码及反编译的字节码指令:
public class TestArg {
public void a() {
int a = 10;
b(a);
}
public int b(int i) {
return i + 100;
}
}
下面对指令进行解释:
aload_0 表示将第一个局部变量this压入操作数栈;
iload_1 表示将第二个局部变量(int型的)压入操作数栈;
invokevirtual 表示调用b方法;
我们可以得出这样的结论,a方法调用b方法并传递参数时流程如下:
- a方法将局部变量表中的变量取出,压入操作数栈
- 为新方法创建一个新的栈帧,入虚拟机栈,将新的栈帧设置为当前栈。
- 将参数从调用者方法a的栈帧中的操作数栈中出栈,然后写入被调用方法b的局部变量表中。
- 根据b方法中的bytecode,执行b方法中的指令
其中23步通过编译后的字节码不能直接看出来,是推测的结果,但不影响我们对a方法的局部变量表进行判断。
从以上流程可以总结出:
a调用b方法并传递参数,并么有对a方法的局部变量表做任何改动。
方法调用是通过操作数栈完成两个栈帧的局部变量表中变量的传递,相当于是将变量槽中的值复制了一份,通过操作数栈粘贴给了被调用方法的参数变量。这也正是值传递的定义。
所以Java是值传递。
参考:https://www.eefocus.com/embedded/279883
https://zhouj000.github.io/2019/03/21/java-base-jvm5/