值传递和引用传递
首先 不管下面说什么, 公论:Java 只有值传递,没有引用传递
官方的话:
值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递(pass by reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。参数传递 可以理解当我们要调用一个方法时,我们会把指定的数值,传递给方法中的参数,这样方法中的参数就拥有了这个指定的值,可以使用该值,在方法中运算了。这种传递方式,我们称为参数传递。
我们来总结一下,值传递和引用传递之前的区别的重点是什么。
值传递 | 引用传递 | |
---|---|---|
根本区别 | 会创建副本(copy) | 不创建副本 |
所以 | 函数中无法改变原始值 | 函数可以改变原始值 |
官方的话也是非常的官方了!
简单点说:
在此之前,我们先搞懂两个概念
实参和形参
public static void main(String[] args) {
int a = 8; // 实参
f(a);
}
public static void f(int a){
System.out.println(a); // 形参
}
实参,就是我们要传递给方法的,在方法外面
形参,就是我们方法签名上定义的参数,在方法里面
那么,值传递和引用传递的区别是什么呢?
简单粗暴来说:
对形参的修改不会影响到实参,那就是值传递,
对形参的修改能够影响到实参,那就是引用传递
例1:
(回到图示) public static void main(String[] args) {
int a = 8; // 实参
f(a);
System.out.println("实参:" + a);
}
public static void f(int a){
a = 16;
System.out.println("形参:" + a);
}
/*打印结果:
形参:16
实参:8
*/
如果我们将基本数据类型的值,传递到方法中,然后在方法内修改形参的值,最后
打印实参和形参。
OK!来看打印结果,可以发现,形参修改了,并没有影响到实参。这很符合值传递。
我们再来看非基本数据类型,也就是对象,
public class Person {
public String name;
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
当我们将一个对象变量,传递到方法中,然后在方法内修改对象的属性,再打印实参和形参
例2:
(回到图示)public static void main(String[] args) {
Person p = new Person("张三");
f(p);
System.out.println("实参:" + p);
}
public static void f(Person p) {
p.name = "李四";
System.out.println("形参:" + p);
}
/*
* 打印结果:
* 形参:Person{name='李四'}
实参:Person{name='李四'}
* */
会发现实参和形参的都被修改了,这样看起来 java 好像也支持引用传递呀!
别急,你别着急!
我们再来看看这个例子,
例3:
(回到图示)public static void main(String[] args) {
Person p = new Person("张三");
f(p);
System.out.println("实参:" + p);
}
public static void f(Person p) {
p =new Person("李四") ;
System.out.println("形参:" + p);
}
/*
*打印结果:
* 形参:Person{name='李四'}
* 实参:Person{name='张三'}
*
* */
如果我们创建一个新对象,并赋值给形参,此时再打印
会发现实参和形参已经互不影响了,
要理解这些现象,我们需要搞懂。。。
在 JVM 中,划分了好几块内存区域,其中就有一个栈空间,和一个堆空间,

我们创建所有的对象都存放在堆中,而基本数据类型和局部变量是存放在栈中的

当传递基本数据类型时,是将数据创建了一个副本,传递到方法中,那自然形参修改也不会影响到实参,符合值传递。
当操作对象时就要注意了,对象是存放在堆中的。

我们拿到的只是对象的引用,通过对象的引用,就可以操作对象。
这也就是说为什么说,java 数据类型,分为两种,一种是基本数据类型,一种是引用数据类型。
我们来回顾 (第二个例子(点击))

当对象引用传递给方法时,其实是创建了一个引用副本,实参和形参都指向了同一个对象,所以通过形参引用操作对象时,显得实参好像改变了。
但实参本身是没有改变的,因为实参就是原先的那个引用嘛,就是一个遥控器,电视机内容改变了,遥控器本身又没有改变。

所以我们将形参重新赋值的时候,实参是不会受到任何影响的。此时形参和实参指向不同的对象。
总结:
java 完全就是值传递的,如果是基本数据类型,那就复制一份值传递给形参,如果是引用数据类型,那就将引用复制一份传递给形参,形参始终拿到的都是一份副本,无论如何,都无法通过形参改变实参,毕竟形参只是操作的副本而已。
内容参考 RudeCrab
作者:走马
出处:https://www.cnblogs.com/zou-ma/p/16101676.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
本博文版权归本博主所有,未经授权不得转载
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?