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

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

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

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

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

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

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

【问题讨论】:

  • 这是一个非常完整的question 示例。没有制作对象的副本,正在制作引用的副本。

标签: java function object pass-by-reference pass-by-value


【解决方案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 中的参数值(或任何其他变量,或任何表达式的值)只能是原语,或引用。不是“对象”。

          【讨论】:

            猜你喜欢
            • 2014-06-07
            • 1970-01-01
            • 2017-01-19
            • 1970-01-01
            • 1970-01-01
            • 2013-11-29
            • 2013-08-13
            • 2021-04-14
            • 2018-08-02
            相关资源
            最近更新 更多