Java只有值传递, 结论 大家都很清楚了.
那么java将方法的实参传递给形参 具体是怎么做的呢?
下面先定义一个测试类Tese 里面只有一个fun方法
public class Test {
void fun(int i){
int b =i;
}
public static void main(String[] args) {
new Test().fun(4);
}
}
局部变量表(本地标量表) 有3个变量
分别是;
this : this 是自动添加的.里面的值是当前对象的引用
i :形参
b:内部的局部变量
查看一下 fun()函数对应的字节码
如下图
0 iload_1 #以读取整数的形式去读取 局部变量表 下标为1的变量的值并压入到操作数栈
1 istore_2 #把操作数栈 栈顶的数值 赋值给 局部变量表下标为2的变量
2 return # 返回结束函数调用
从上面的字节码可以得知
做的操作只是 把i的值复制给b. 已经完成了把常量4 赋值给形参i的 传值操作
传参操作并没在被调用函数的字节码里面明文显示,
那我们现在返回去看一下调用函数 main() 做了那些操作 是不是可能传参操作在调用函数里面.
main()函数字节码如下
0 new #2 <Test> #创建一个Test 类的对象
3 dup #复制操作数栈顶值,并将其压入栈顶,也就是说此时操作数栈上有连续相同的两个对象地址
4 invokespecial #3 <Test.<init>> #调用实例初始化方法<init>:()V
7 iconst_4 #把常数 4 压入到操作栈中
8 invokevirtual #4 <Test.fun> #传参操作在这条指令
11 return # 返回结束函数调用
invokevirtual 命令
在官方文档中这样描述:
假设objectref的类型为C,实际调用的方法将按照下面流程来查找:
- 如果C包含了一个方法m的声明,该声明重写了解析出来的方法,则m为实际调用的方法,查找终止。
- 否则:如果C有父类,则自下而上递归的在C的直接父类中执行第一步的查找。
- 如果还没有查找到,则抛出AbstractMethodError错误。
如果解析出来的方法有参数的话,在操作数栈上,所有的参数的值必须按照方法描述中规定的数量,类型和顺序自上而下跟在objectref后面。
而且如果解析出来的方法不是native的,所有的参数和objectref从操作数栈中弹出。在JVM栈上为当前准备调用的方法创建一个新的栈帧。
Objectref和所有参数被按照如下顺序作为新栈帧的局部变量,objectref占slot0,arg1占slot1(否则,如果arg1为long或double类型,则占slot1和slot2),以此类推。对于float类型参数,在存入局部变量表之前会先进行值集转换。新的栈帧成为当前栈帧,JVM的PC设置为即将调用方法的第一条指令的操作码,程序执行从第一条指令继续进行。
由此可以得知java传参操作 发生在主调代码块.由命令 invokevirtual 实现