一篇关于Java价值转移的文章

云栖息地编号信息:[点击查看更多行业信息]

在这里,您可以找到来自不同行业的第一手云信息。你还在等什么?来吧。

让我们从一个问题开始:

一篇关于Java价值转移的文章

一篇关于Java价值转移的文章

检查答案:

一篇关于Java价值转移的文章

值与引用

为了纠正值传递和引用传递中的一些误解,这里讨论的不是值类型和引用类型,而是赋值操作过程中各个部分的名称。

以上述问题为例,有p1点=新点(0,0);

一篇关于Java价值转移的文章

变量p1存储实际对象的地址,通常称为“引用”,引用指向实际对象。我们称实际对象为引用的值。如果我们有p1=新的点(3,3),赋值运算符=实际上完成了将引用指向值的地址的工作;情况是这样的:

一篇关于Java价值转移的文章

我们应该注意到堆中的对象Print(0,0)没有改变,只有引用p1指向的地址改变了。

这些是值和引用,而值转移和引用转移与这些无关。

值传递和引用传递

我们可以在在线数据中找到价值转移的定义,主要是这样的:

当调用该方法时,实参引用的副本被传递到该方法中,因此在形参上的任何操作都不会影响实参

这句话本身对价值转移的定义是相对准确的,但是由于前后矛盾和概念的盲区,让我们理解歧义,这里有三个一般的歧义:

因为传递了引用,所以应该传递引用。为什么称之为价值传递?

引用本身也是一个值,本质上是一个指针,所以所有的传递都是值传递。

他们中的大多数人会被上述概念的后半部分所误导:“形参的任何行动都不会影响实参",因为我们可以通过在上述采访问题中使用形参,(如p1.setLocation(5,5))来轻易地改变实参;或以下代码

一篇关于Java价值转移的文章

大多数时候,我们对价值转移有疑问。最根本的原因是我们不理解价值转移和参考转移在描述什么。我们错误地认为它们的名字是不言自明的:传递的是值传递,传递的是引用传递,java是值传递,这意味着Java在调用方法时传递值。这就是我们上面提到的概念盲点。价值转移和参考转移的正确解释如下:

“按值调用”和“按引用调用”描述了调用函数时参数的评估策略,描述了调用函数时的评估和取值方法,而不是传递的内容。

值和引用描述了两种内存分配方法:值在堆上分配,引用在堆栈上分配(这里区分值类型和引用类型)。然而,值传递和引用传递描述了一个参数评估策略,它们之间没有依赖关系。

总之,我们可以得出这样的结论:java是值传递的说法也是不准确的,完整的说法应该是Java在调用函数时使用了值传递的评估策略。严格地说,评估策略不仅包括值传递和引用传递,还包括共享对象传递(通过共享调用)和值返回传递(通过复制还原调用)。然而,这些概念对我们理解Java值传递没有帮助。

在阐明了值转移和引用转移所描述的具体内容之后,我们现在来看一下关于Java值转移概念的第三个歧义:形参的任何操作都不会影响实参。以上面的colorList代码为例,我们已经知道,当调用函数时,值转移的评估策略会将实参引用的副本传递到函数中,所以当调用removeFirst()方法时,有:

一篇关于Java价值转移的文章

“形参颜色列表”作为实参颜色列表的副本,它们注册相同的地址,并且都指向堆中的相同实例颜色列表[蓝色、红色、灰色]。

我们在removeFirst()方法中操作的是形参颜色列表。但是刚才有人说,形参和实参都只存储实例对象的地址,真正的对象仍然是他们都指向的堆中的颜色列表。我们在removeFirst()方法中调用的remove()是实例对象ColorList本身提供的一个函数,它可以自行更改。因此,当colorList '。remove(0)是在removeFirst()方法中执行的,形参ColorList所指向的实例对象ColorList '变成ColorList[RED,GRAY],而实参ColorList仍然指向此实例对象,因此当方法调用完成时,实例对象会发生变化。

这样看来,“形参的任何行动都不会影响实参"”的说法似乎并不严格。那么,这一声明将在什么情况下生效呢?我们将把removeFirst()方法更改为以下代码:

一篇关于Java价值转移的文章

新的removeFirst()方法包括:

一篇关于Java价值转移的文章

根据价值转移的评估政策,传递实参参考资料副本的步骤保持不变。在“值和引用”部分,我们说过赋值操作符的实际工作是指向值的引用。在这个removeFirst()方法中,我们重新分配了对形参颜色列表的引用,因此现在它指向一个新的实例颜色列表[红色灰色],但是,当removeFirst()方法在执行后退出时,形参颜色列表也将被回收,而实参颜色列表[蓝色红色灰色]所指向的颜色列表没有改变(它是形参,所指向的实例,但是在该方法退出后,方法参数颜色列表将被回收,并且它所指向的实例将成为一个垃圾对象)。

对价值转移概念的三个模糊之处进行了解释。我们可以在这里给出一个正确而完整的java价值转移概念:

Java使用一种叫做值传递的评估策略。该策略将在价值传递过程中复制实参的参考,并将该副本传递给方法形参,因此任何对形参的重新分配都不会影响实参

在下一节,我们将分析开头的问题。如果您仍然不太理解Java值传递,我将在下一节分享一项技能,以帮助您更彻底地理解Java值传递。

面试题解析

回到开始的问题,在modifyPoint()方法中,前三行代码使用一个临时变量tmpPoint来交换形参P1和p2的值,因此在该方法中,形参P1实际上指向实参P2,形参P2指向实参P1:

一篇关于Java价值转移的文章

关于Java的值传递策略,有一个更微妙的理解,也就是说,一个函数的参数传递过程可以通过将其等同于赋值运算符=来完全理解。当我们调用modifyPoint(p1,p2)时,我们可以理解在方法内部有形参P1 '=实参P1。形参P2 '=实参P2,所以我们在P1 '和P2 '操作的方法实际上是临时变量,它的生命周期仅限于该方法。

形参P1和形参P2交换意见后,堆栈的信息简单表述为:

一篇关于Java价值转移的文章

然后是p1 '。调用了setLocation(5,5);正如我们在前一节中所说的,如果实例对象本身提供了一个改变自身的方法,那么实参将在形参调用该方法后被改变,因为它们都指向同一个实例,所以实参P2也变成了[5.5]。

代码转到下一行p2'=新点(5,5);基于对整篇文章的讨论,我们可以直接跳过这一行,因为形参的重新分配操作不会影响实参。关于堆栈的最终信息如下:

一篇关于Java价值转移的文章

所以最后的答案很明显:[0,0],[5,5]

[云起在线教室]产品和技术专家每天分享!

课程地址:https://yqh.aliyun.com/zhibo

立即加入社区,与专家面对面,并了解课程的最新进展!

[云栖在线课堂社区]https://c.tb.cn/F3.Z8gvnK

发布者:2020-04-12

作者:luckykelan

这篇文章来自“掘金”。如果你知道相关信息,你可以关注“掘金”