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个变量


 

java 接受文件 传参 java中如何传参_java


分别是;


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  实现