聊聊java代码中的值传递、引用传递区别是一道Java 常见面试题 ,值传递和引用传递是很基础却又容易让人迷糊的知识点。不少小伙伴虽然会在代码里用,但对它们的原理却一知半解。今天咱就好好唠唠这俩概念,帮大家彻底搞清楚。

引用传递:就像用快捷方式访问资源

在Java里,引用传递的场景很常见。比如说,在一个方法里调用另一个方法,传递的参数是数组,当在子方法里对这个数组进行增加或删除元素的操作时,原方法里的数组也会跟着改变。这是为啥呢?其实啊,数组传递给子方法时,传递的并不是数组本身,而是数组对象的引用。打个比方,这个引用就好比电脑桌面上创建的快捷方式,通过它可以访问到硬盘(比如D盘)里的某个资源,而真正的资源(数组对象)存放在堆内存中。

咱用代码详细解释一下。看下面这段代码:

// 创建一个Integer对象,值为1 Integer a = 1; 

在Java虚拟机(JVM)中,会在堆内存里创建一个值为1的Integer对象。与此同时,在堆栈中会创建一个变量a,这个a就是一种引用,它指向堆内存里值为1的Integer对象,就好像给这个对象贴上了一个标签。

// 创建另一个Integer对象b,并将a的值赋给b Integer b = a; 

当执行这行代码时,在堆栈中又创建了一个变量bb同样指向堆内存中值为1的那个Integer对象,和a的指向是一样的。这时候,如果对b进行修改:

// 修改b的值 b = 2; 

实际上修改的是堆内存中那个Integer对象的值。因为ab指向同一个对象,所以a的值也会跟着变动(这里要注意,在Java中Integer是不可变类,这里修改b其实是让b指向了一个新的Integer对象,不过为了便于理解引用传递原理,先按上述逻辑理解 )。

不仅是Integer对象,像数组、集合以及自定义的类,在变量赋值的时候,都属于引用传递。这些变量保存的只是对象在堆内存中的地址,不管通过哪个变量去操作,实际修改的都是堆内存里的同一个对象。

值传递:基础数据类型的“专属”传递方式

说完引用传递,再来讲讲值传递。值传递主要针对Java中的基础数据类型,像intcharfloatdouble等。和引用传递不同,基础数据类型的变量及其值是存储在堆栈中的,而不是堆内存。

咱还是用代码来说明:

// 创建一个int类型的变量a,值为1 int a = 1; 

这里的a和值1都存放在堆栈中。

// 创建另一个int类型的变量b,并将a的值赋给b int b = a; 

执行这行代码后,相当于在堆栈中重新拷贝了一份a的值给b。后续对b进行修改:

// 修改b的值 b = 2; 

此时,b的值变了,但a的值并不会受到影响,依然是1。这就是典型的值传递,每个变量都有自己独立的存储空间,修改一个变量不会影响到另一个。

String类型:看似引用传递,实则值传递

这里有个特殊情况要注意,就是String类型。String不属于Java的基本数据类型,从使用方式上看,它好像和Integer等引用类型差不多,很多人会误以为它是引用传递。但实际上,String是值传递。

这是因为String类是用final修饰的,意味着它的值一旦创建就不能被修改。如果对String变量进行重新赋值,比如:

// 创建一个String类型的变量str,值为"hello" String str = "hello"; // 重新给str赋值 str = "world"; 

这里并不是修改了原来"hello"这个字符串的值,而是重新创建了一个"world"字符串对象,然后让str指向这个新对象。所以,String类型在传递和赋值时,遵循的值传递的规则。

到这儿,Java里的值传递和引用传递就讲得差不多了。要是你对今天讲的内容还有啥疑问,欢迎在评论区留言,大家一起讨论讨论!