从jvm字节码指令 看待java值传递与是否存在引用传递的问题

ps

最近在看java究竟是只有值传递还是值传递和引用传递都有这个问题的博客时,各有各的说法,有一篇博客的评论使我动了很大的好奇心
博客地址:http://www.cnblogs.com/binyue/p/3862276.html
大概内容
如下的一行代码,调用test2方法时,传递过来的对象是属于值传递还是引用传递

public class Test {
    public static void main(String[] args) {
        Test t = new Test();
        MyObj obj = new MyObj();
        t.test2(obj);// 这里传递的参数obj就是引用传递
//        System.out.println(obj.b);
    }

    public void test2(MyObj obj) {
        obj = new MyObj(); // 纠结在这一行
        obj.b = 100;
    }
}

class MyObj {
    public int b = 99;
}

我的疑问

1.通过这个开始了解到底调用方法时传递的是值传递还是引用传递
2.调用方法时,如何确定实参给形参时,确实开辟了一份栈内存给形参

我的解决方式

我采用javap 看class指令,来确认传递的是值还是引用

javap -c Test.class

但是面临了一个问题,我对jvm不是很熟,只知道字节码的反编译命令,所以我采用了循序渐进的方式
1.先纯main方法时,编译,然后查看字节码
2.main方法输入 Test t = new Test(); 再编译,再查看
3.依次类推,一行行的代码进行编译,和查看
得到以下结果

字节码+查看字节码大全的解析
public class com.fanfan.test.Test {
///=========生成默认的无参数构造函数 start =======
  public com.fanfan.test.Test();     ///
    Code:
       0: aload_0						///aload_0 此指令告诉虚拟机,将局部变量this放入操作栈里。
       1: invokespecial #8                  // Method java/lang/Object."<init>":      ///编译时方法绑定调用方法。  也就是绑定主方法main
()V
       4: return						///void函数返回。
///=========生成默认的无参数构造函数 start =======
  public static void main(java.lang.String[]);
    Code:
	 ///   =====start  new  test对象====
       0: new           #1                  // class com/fanfan/test/Test   ///new  Test对象
       3: dup								///复制栈顶一个字长的数据,将复制后的数据压栈。
       4: invokespecial #16                 // Method "<init>":()V    ///运行时方法绑定调用方法 也就是 对象的无参数构造函数
       7: astore_1							///将栈顶引用类型值保存到局部变量1中。 也就是把new好的对象栈空间地址交给 t
	///   =====end  new  test对象======
   ///   =====start通过 new  test对象很容易知道 这一块new了 Object对象====
	  8: new           #17                 // class com/fanfan/test/MyObj
      11: dup
      12: invokespecial #19                 // Method com/fanfan/test/MyObj."<in
it>":()V
      15: astore_2
	  	///   =====end 通过 new  test对象很容易知道 这一块new了 Object对象======
	
      16: aload_1							///从局部变量1中装载引用类型值入栈。  把Test对象的实例t
      17: aload_2							///从局部变量2中装载引用类型值入栈。 把MyObj对象的实例obj
      18: invokevirtual #20                 // Method test2:(Lcom/fanfan/test/My      ///调用方法test2
Obj;)V
      21: return

  public void test2(com.fanfan.test.MyObj);
    Code:
	//=======obj = new MyObj(); ==
       0: new           #17                 // class com/fanfan/test/MyObj
       3: dup
       4: invokespecial #19                 // Method com/fanfan/test/MyObj."<in
it>":()V
       7: astore_1
	//=======obj = new MyObj(); ==

       8: aload_1
       9: bipush        100
      11: putfield      #29                 // Field com/fanfan/test/MyObj.b:I
      14: return
}
上述字节码对应的代码
package com.fanfan.test;

public class Test {
    public static void main(String[] args) {
        Test t = new Test();
        MyObj obj = new MyObj();
        t.test2(obj);// 这里传递的参数obj就是引用传递
//        System.out.println(obj.b);
    }

    public void test2(MyObj obj) {
        obj = new MyObj(); // 纠结在这一行
        obj.b = 100;
    }
}

class MyObj {
    public int b = 99;
}

结果

1.从字节码指令的16,17确实可以看出 ,传递的只是值传递,也就是类的实例

16: aload_1							///从局部变量1中装载引用类型值入栈。  把Test对象的实例t
  17: aload_2							///从局部变量2中装载引用类型值入栈。 把MyObj对象的实例obj

2.对于第二问,目前还是不敢十分确定调用方法时,实参传递给形参时又开辟了一块内存地址,因为从字节码中看出,只是将局部变量的值重新压入栈内存中。
所以我斗胆认为,实参传递给形参时,并没有开辟一块存区域,只是调用test2方法占用的内存区域

参考博客

jvm入门
java字节码入门(上)
https://blog.csdn.net/xiandafu/article/details/51458791
字节码大全表
https://www.cnblogs.com/longjee/p/8675771.html
句柄
https://blog.csdn.net/lly983909814/article/details/72529773

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值