转载

Java是传值还是传址

传值和传址有什么区别?Java是传值还是传址?

开始

Java在传参时,是传值还是传址?

传值和传址

假设要将A传到B。如果是传值,就意味着将A中存放的值复制一份给B,B存的是跟A一样的值,B的改变,不会影响到A。如果是传址,则是将A的地址复制给B,改变B时,事实上会根据B中存放的地址找到A,所以,B的改变,也就代表A的改变。

传值和传址

Java是传值

java是传值。首先,你要明确这个概念,然后,我们来看看,为什么这样说?

在java中,没有指针这个概念。传参时,确实是将A的值复制了一份到B,B的改变并不会影响A中的值。说到这里,同学就该疑惑了,说这怎么可能呢?没关系,我们继续往下聊。

分三种情况来讨论这个问题。分别是基本类型,对象和数组,还有String。

我们假设有数据V,赋值给变量A,要传参到变量B。

基本类型

先来看基本类型。假设V是一个基本类型,那么,A中存放的就是数据V本身。此时,复制一份到B,意味着B中也存储了数据V1。注意,这里特别注明V1,代表的是V和V1的值相同,它们是同样的值,但不是同一个值。所以,对B的操作,不会影响到A,这是比较容易理解的。

对象和数组

再来看对象和数组。假设V是一个对象或数组,那么,A中存放的就是数据V在堆中的地址(V也可以存放在其它内存空间中),我们称之为引用类型。此时,复制一份到B,意味着B中也存储了数据V的地址。注意,这里,A和B中的值确实也是一样的,但是,不是同一个值。那么,接下来我们对B操作,看看会发生什么。我们分两种情况来讨论。 宝宝起名宝典

第一种情况,我们假设修改了对象V的某个属性或数组中的某个元素。此时,实际上做的是,根据B中存储的值,找到对应的地址,修改了对应地址中的值。这样,由于A和B存储的是同样的地址,所以,当再通过A去获取对应地址中的值时,就会发现,A变量也改变了。

第二种情况,我们创建了一个新的对象或数组,并将其赋值给B。那么,此时A会改变吗?我们说,不会,因为A和B原来只是存储了同样的值,并不是同一个值,所以,修改了B中的值,并不会影响到A,A还是指向它原来指向的对象。总结一下就是,当修改B本身的值时,不会影响A,当修改的是B中地址对应的对象或数组时,会影响到A。

String常量池

最后,我们来看String。我们知道,String并不是一个基本类型,那么,它是不是应该和对象或数组的特性一样呢?不是,因为String用了一个特殊的机制,叫做常量池。当你新建一个String对象(通过字面量的方式)时,事实上,JVM真正做的是,在常量池中找对应的值,找到就把地址给变量,找不到,就在常量池中新建一个值,再把地址给变量。这里,有两层含义。

第一, 如下,a和b存储的实际是同样的常量池地址。

第二, a中存储的地址已经改变了,但是,常量池中,原先存放hello的位置中的值,还是没有改变,JVM会在常量池中重新找一个地方,存放hello world,并把地址给a。

所以,当把A传给B时,通过字面量的方式修改B的值,事实上不会对A造成影响。而如果是通过new的方式,新建一个String对象赋值给B,那就和对象或数组的情形一样了,一会对A造成影响。

举个栗子

基本类型时,A好比是一张纸条,当要传值给B时,事实是把纸条上的内容抄给了B,所以,B去修改自己纸条上的内容,当然不会对A产生任何影响。

引用类型时,A好比是一把仓库钥匙,当要传值给B时,事实上是把钥匙配了一把给B。B把自己钥匙扔掉,或者是盘几年,包浆了,都不会对A产生影响,但是,B如果拿着钥匙打开仓库,把仓库里的东西都卖了,那当A打开仓库时,自然就会吓得一屁股坐到了地上。

常量池时,A好比是一张纸条,当要传值给B时,事实是把纸条上的内容抄给了B。听起来好像和基本类型是一样的,其实不然。因为纸条上写的是一个字典上对应的页码。当B修改自己的纸条时,当然不会对A有影响。而当B修改字典上对应页码的内容时,事实上,B是不能这么干的。字典有防御功能,它会在字典中找到B需要的值,把相应的页码给B。所以,这也不会对A造成影响。

结论

Java是传值,基本类型时,复制的是值,引用类型时,复制的是引用,也就是地址。

原文  https://segmentfault.com/a/1190000019721698
正文到此结束
Loading...