作为函数参数传递的Java对象[重复]

Posted

技术标签:

【中文标题】作为函数参数传递的Java对象[重复]【英文标题】:Java Objects passed as Function Parameters [duplicate] 【发布时间】:2016-10-16 04:44:28 【问题描述】:

以下关于 Java 的说法是真是假?

在 Java 中,当一个类或对象的实例被指定为方法的参数时,会生成该对象的副本

我知道 Java 中的函数是按值传递的,这意味着正在制作对象的副本?

但同时,如果 java 对象是引用,而你传递一个引用,这与实际数据的副本是不同的,不是吗?

如果你传递一个引用,当引用被重新分配时,对象将被重新分配,使得 Java 传递引用而不是传递值?

如您所见,我非常对此感到困惑

【问题讨论】:

这是一个非常完整的question 示例。没有制作对象的副本,正在制作引用的副本。 【参考方案1】:

在java中,一切都是通过副本传递的。

原语通过副本传递。所以在函数内部改变它不会反映在外部。

对于对象传递给函数的是引用的副本(不是对象的副本)。这意味着更改函数内部的属性外部引用会看到修改,但更改引用本身(例如分配 null)不会反映在函数外部。


请举一些例子来更好地解释。

改变原语的函数:

public void notChange(int a) 
    a = 3;
    // Here a is 3


int a = 0;

notChange(a);
// Here a is 0

对于改变对象内部内容的函数

public void changeContent(List<String> list) 
    list.add("x");
    // Here list has one more element


List<String> list = new ArrayList<String>();
// Here list has size 0
changeContent(list);
// Here list has size 1

对于改变对象引用的函数

public void changeReference(List<String> list) 
    list = null;


List<String> list = new ArrayList<String>();
changeReference(list);
// Here list is not null

【讨论】:

【参考方案2】:

如果是对象,则传递一个引用的副本。请注意,这并不意味着传递了对象本身的副本。您对对象所做的任何更改也将反映在原始对象中。如果您没有正确复制对象,这可能会导致一些疯狂的事情。使用复制构造函数或类似复制对象的东西。

另外,阅读deep and shallow copy。

【讨论】:

【参考方案3】:

这是一个在c++中按值传递和按引用传递的例子。在此示例中,java 的行为类似于按值传递版本。值是指向对象的指针。

#include <stdio.h>

class Obj
  int value;
  public:
    Obj(int v)
        value = v;
    
    void echo()
        printf("%d\n", value);
    
;

void byValue(Obj* obj)
    obj = new Obj(-1);
    obj->echo();


void byReference(Obj*& obj)
    obj = new Obj(-1);
    obj->echo();


int main(int argc, char** args)
    Obj* o = new Obj(1);
    byValue(o);
    o->echo();
    byReference(o);
    o->echo();
    return 0;

(抱歉泄漏,这不是一个好的实践示例) 输出是:

-1 
1
-1
-1

【讨论】:

【参考方案4】:

我会从你的第一个问题开始一步步回答你:

在 Java 中,当一个类或对象的实例被指定为 方法的参数,正在制作该对象的副本

这是 false,当您将对象传递给方法时,Java 永远不会复制它,正如 Davide Lorenzo 所说,您正在传递对对象的引用,不是对象本身,因此如果该方法修改了类的某些属性,那么您的值也会在该方法之外进行修改。

所以我们可以回答第二个和第三个问题:

我知道 Java 中的函数是按值传递的,这意味着 正在制作对象的副本?

不,Java 不会复制。正如 Davide Lorenzo 所说,您传递的是引用的副本而不是对象的副本。

但同时,如果 java 对象是引用并且你传递了一个 参考,这与实际数据的副本不同吗?

是的,传递引用与传递对象的副本确实不同。 我将举例说明一切。 假设我们有一个具有 color

属性的对象 Flower
public class Flower
    String color = "red";

enter code here

我们可以想象AnotherObject的方法setColor

public void setColor(Flower flower, String color_string)
    flower.color = color_string;

我们可以有以下情况

public static void main(String args[])
   Flower myFlower = new Flower();
   AnotherObject otherObject = new AnotherObject();

   otherObject.setColor(myFlower, "yellow");
   System.out.println("The color of the flower is: "+myFlower.color);

这段代码的输出将是:

The color of the flower is yellow

这就是为什么你要传递对象的引用,而不是对象本身。

现在您可以问为什么 Java 被视为 按值传递? 在this previous post 上有一个非常有趣的讨论,我会引用它的最佳答案:

Java 总是按值传递。不幸的是,他们决定打电话 指针引用,从而使新手感到困惑。因为那些参考 按值传递。

最后但并非最不重要的一点是,只有原始类型不是通过 Java 中的引用来管理的,所以传递 int 与传递 Integer 确实不同,我建议你看看this post关于这个论点。

【讨论】:

【参考方案5】:

在 Java 中,当一个类或对象的实例被指定为 方法的参数

这就是你出错的地方。每个参数都有一个类型。 Java 中仅有的类型是原始类型引用类型。因此,Java 中的参数值(或任何其他变量,或任何表达式的值)只能是原语,或引用。不是“对象”。

【讨论】:

以上是关于作为函数参数传递的Java对象[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何传递和使用任意lambda函数作为参数[重复]

java数组作为参数传入函数怎么让他不变化

C#将函数作为参数传递[重复]

在函数中传递多个html元素作为参数[重复]

将函数作为参数传递[重复]

在函数c ++中将变量作为默认参数传递[重复]