Java方法传参到底传的是什么?值传递&引用传递辨析

引言

本文主要讲解Java方法传参、值传递、引用传递,其中涉及到JVM的相关知识,最近弥补了这一块,发现理解很多问题都变得豁然开朗了,知其所以然!(JVM在我其他博客中有详细辨析)
在这里插入图片描述
在刷力扣题目时,遇到这样一个问题,当我把一个变量传进dfs方法后,无论递归中如何对该变量赋值,最终都没有生效,今来探究其原因,说到底还是Java值传递、引用传递的问题:

方法传参

Java的方法传值,有基本数据类型以及引用类型两种:

int num = 10;   //基本类型
String str = "hello";  //引用类型

在这里插入图片描述

这里num是基本类型,str是引用类型,str是引用类型,对于引用类型来说,它本质上保存的是一个地址,指向了 "hello"这个字符串。

再还要来理解一下赋值操作(=)的具体含义:

基本类型的赋值,是直接对其保存的值进行修改的(比如这里的num直接可改为100),而引用类型的赋值,本质上是改变了它指向的对象而已,原来指向的对象并没有改变:

在这里插入图片描述

继续看方法的调用:

在方法中传参数时,实际上是进行了赋值操作

作者:Intopass
链接:https://www.zhihu.com/question/31203609/answer/50992895
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

第一个例子:基本类型
void foo(int value) {
    value = 100;
}
foo(num); // num 没有被改变

第二个例子:没有提供改变自身方法的引用类型
void foo(String text) {
    text = "windows";
}
foo(str); // str 也没有被改变

第三个例子:提供了改变自身方法的引用类型
StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder.append("4");
}
foo(sb); // sb 被改变了,变成了"iphone4"。

第四个例子:提供了改变自身方法的引用类型,但是不使用,而是使用赋值运算符。
StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder = new StringBuilder("ipad");
}
foo(sb); // sb 没有被改变,还是 "iphone"。

从JVM视角来看,所有的线程共享的区域是堆、元空间;每一个线程有独占的虚拟机栈、本地方法栈、程序计数器。那么对于传进参数的的这个方法,自然会加载到当前线程的虚拟机栈中,所以呢,对于每个方法的局部变量来说,是绝对无法被其他方法,甚至其他线程的同一方法所访问到的,更不用谈修改了。

当我们在方法内部去声明变量时(int i =0, Object obj = null),仅仅是在栈(Stack)中加入了局部变量,并没有影响到堆(共享区域)。当我们外部new Object() 对象时,会在堆中开辟一段内存空间并初始化该对象实例,如果给这个对象赋值给方法内的obj局部变量时,仅仅只是把栈中的这个obj局部变量的地址指向改变了到了新new的Object而已。

总结:

  1. 如果参数是基本类型,Java方法参数传递的是基本类型值的拷贝
  2. 如果参数是引用类型,Java传递的是所引用的对象在堆中地址值的拷贝

所以如果想把某个对象传进方法,并且还想在方法内部修改它,则必须得调用这个对象自己的成员方法去修改,才能对堆上这个对象做实际的修改,如果只是赋值操作(=),那么仅仅改变的是方法内局部变量的指向而已,并没有真正改变原来的对象值。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值