前言
🍊缘由
值传递和引用传递,傻傻分不清楚?
🐣闪亮主角
大家好,我是JavaDog程序狗。今天咱们来唠唠Java里一个让新手头疼,老手也偶尔会迷糊的事儿——值传递和引用传递。
现在,我就结合实际案例,用大白话给你分析分析,让你一次性搞懂:啥是值传递?啥是引用传递?为啥Java里只有值传递?哪些情况容易让人误以为是引用传递?
😈你想听的故事
狗哥之前带过一个小徒弟,有一次他写了个方法,想在方法里修改传入的对象。结果发现,对象在方法里改了,出了方法又变回原样了。小徒弟一脸懵圈地跑来问我:“老狗,这咋回事啊?我明明改了对象,咋就没生效呢?”
我一看,原来是他没搞清楚值传递和引用传递的区别。于是,我就给他好好上了一课,让他明白了其中的奥秘。今天,我就把这些经验分享给大家,让你们也能少走弯路。
正文
🎯主要目标
1. 啥是值传递和引用传递?为啥Java里只有值传递?
2. 哪些情况容易让人误以为是引用传递?
3. 如何正确地在方法里修改对象?
4. 狗哥的实战经验总结,让你从此告别传递困惑!
🍪目标讲解
一. 啥是值传递和引用传递?
1. 你眼中的传递:简单直接!
在程序员的世界里,方法调用和参数传递是再常见不过的操作了。比如下面这段代码:
public class PassExample {
public static void main(String[] args) {
int num = 10;
modifyNumber(num);
System.out.println("num 的值是:" + num);
}
public static void modifyNumber(int number) {
number = 20;
}
}
这段代码看起来很简单,就是定义了一个变量num
,然后把它作为参数传递给modifyNumber
方法,在方法里把参数的值改成了20。但是,当我们运行这段代码时,会发现输出的结果是num 的值是:10
,而不是20
。这是为啥呢?这就涉及到值传递和引用传递的概念了。
2. 值传递闪亮登场:我只复制,不改变原数据!
值传递,简单来说,就是在方法调用时,把实际参数的值复制一份传递给形式参数。也就是说,方法里操作的是复制后的副本,而不是原数据。就像你有一份文件,你复印了一份给别人,别人在复印的文件上修改,不会影响你原来的文件。
在上面的例子中,num
的值是10
,当我们把num
作为参数传递给modifyNumber
方法时,实际上是把10
这个值复制了一份给number
。在modifyNumber
方法里,我们把number
的值改成了20
,但这只是修改了副本的值,原数据num
的值并没有改变。
3. 引用传递:我能直接改变原数据!
引用传递,是指在方法调用时,把实际参数的引用(也就是内存地址)传递给形式参数。这样,方法里操作的就是原数据,而不是副本。就像你把文件的存放地址告诉别人,别人可以直接去那个地址修改文件,这样就会影响你原来的文件。
不过,需要注意的是,Java里只有值传递,没有引用传递。很多人会误以为Java里有引用传递,是因为在处理对象时,会出现一些看似是引用传递的情况。
4. Java里的对象传递:其实还是值传递!
在Java里,对象变量存储的是对象的引用(内存地址)。当我们把对象作为参数传递给方法时,实际上是把对象的引用复制了一份传递给方法。也就是说,方法里操作的是复制后的引用副本,而不是原引用。
看下面这个例子:
class Person {
String name;
public Person(String name) {
this.name = name;
}
}
public class ObjectPassExample {
public static void main(String[] args) {
Person person = new Person("狗哥");
modifyPerson(person);
System.out.println("person 的名字是:" + person.name);
}
public static void modifyPerson(Person p) {
p.name = "张三";
}
}
在这个例子中,我们创建了一个Person
对象person
,并把它作为参数传递给modifyPerson
方法。在modifyPerson
方法里,我们修改了p
的name
属性。运行这段代码,会发现输出的结果是person 的名字是:张三
,好像对象被修改了,就像引用传递一样。
但实际上,这还是值传递。我们传递的是person
对象的引用副本,虽然副本和原引用指向同一个对象,但它们是两个不同的变量。在方法里,我们通过副本引用修改了对象的属性,所以对象本身被修改了。但如果我们在方法里让副本引用指向另一个对象,原引用是不会受到影响的。
看下面这个例子:
class Person {
String name;
public Person(String name) {
this.name = name;
}
}
public class ObjectPassExample2 {
public static void main(String[] args) {
Person person = new Person("狗哥");
changePerson(person);
System.out.println("person 的名字是:" + person.name);
}
public static void changePerson(Person p) {
p = new Person("张三");
}
}
在这个例子中,我们在changePerson
方法里让p
指向了一个新的Person
对象。运行这段代码,会发现输出的结果是person 的名字是:狗哥
,原对象并没有被改变。这就说明,我们传递的是引用副本,而不是原引用。
二. 哪些情况容易让人误以为是引用传递?
1. 修改对象属性:看似引用传递,实则值传递!
就像上面的Person
对象例子,我们在方法里修改了对象的属性,看起来好像是引用传递。但实际上,我们只是通过引用副本修改了对象本身,而不是修改了引用。
2. 数组传递:同样是值传递!
数组在Java里也是对象,当我们把数组作为参数传递给方法时,也是传递的数组引用副本。看下面这个例子:
public class ArrayPassExample {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
modifyArray(arr);
for (int num : arr) {
System.out.print(num + " ");
}
}
public static void modifyArray(int[] array) {
array[0] = 10;
}
}
在这个例子中,我们在modifyArray
方法里修改了数组的第一个元素。运行这段代码,会发现输出的结果是10 2 3
,数组被修改了。但这还是值传递,我们传递的是数组引用副本,通过副本引用修改了数组本身。
三. 如何正确地在方法里修改对象?
1. 修改对象属性:直接修改!
如果我们想在方法里修改对象的属性,直接通过引用副本修改就可以了。就像上面的Person
对象和数组例子一样。
2. 返回修改后的对象:重新赋值!
如果我们想让方法返回一个修改后的对象,并且让原引用指向这个新对象,我们可以在方法里返回修改后的对象,然后在调用方法的地方重新赋值。看下面这个例子:
class Person {
String name;
public Person(String name) {
this.name = name;
}
}
public class ReturnModifiedObjectExample {
public static void main(String[] args) {
Person person = new Person("狗哥");
person = changePerson(person);
System.out.println("person 的名字是:" + person.name);
}
public static Person changePerson(Person p) {
p = new Person("张三");
return p;
}
}
在这个例子中,我们在changePerson
方法里创建了一个新的Person
对象,并返回了这个对象。在main
方法里,我们把返回的对象重新赋值给person
,这样person
就指向了新的对象。
四. 狗哥的实战经验总结!
-
牢记Java只有值传递: 无论传递的是基本数据类型还是对象,都是值传递。传递的是值的副本或者引用的副本。
-
区分修改对象属性和修改引用: 修改对象属性是通过引用副本修改对象本身,而修改引用是让引用指向另一个对象。
-
正确处理对象修改: 如果想修改对象属性,直接通过引用副本修改;如果想让原引用指向新对象,通过返回值重新赋值。
-
理解原理,避免混淆: 搞清楚值传递和引用传递的区别,以及Java里只有值传递的原因,就能避免很多传递困惑。
🍈猜你想问
如何与博主联系进行探讨
关注公众号【JavaDog程序狗】
公众号回复【入群】或者【加入】,便可成为【程序员学习交流摸鱼群】的一员,问题随便问,牛逼随便吹,目前群内已有超过380+个小伙伴啦!!!
2. 踩踩博主博客
里面有博主的私密联系方式呦 !,大家可以在里面留言,随意发挥,有问必答😘
🍯猜你喜欢
文章推荐
【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)
【项目实战】SpringBoot+uniapp+uview2打造H5+小程序+APP入门学习的聊天小项目
【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序
【模块分层】还不会SpringBoot项目模块分层?来这手把手教你!