【问题标题】:Confused, whether java uses call by value or call by reference when an object reference is passed? [duplicate]困惑,java在传递对象引用时是使用按值调用还是按引用调用? [复制]
【发布时间】:2012-05-31 18:45:08
【问题描述】:
public class program1{

    public static void main(String args[]){

        java.util.Vector vc=new java.util.Vector();

        vc.add("111");
        vc.add("222");

        functioncall(vc);

        vc.add("333");

        System.out.println(vc);

    }

    public static void functioncall(java.util.Vector vc){     

        vc=null;    

    }
}

上述程序的输出是[111,222,333]。但是,当我运行以下程序时,输出为 [333]。当我们传递引用时感到困惑,无论是按值调用还是按引用调用,它是如何工作的?以及为什么

public class program1{

    public static void main(String args[]){

        java.util.Vector vc=new java.util.Vector();

        vc.add("111");
        vc.add("222");

        functioncall(vc);

        vc.add("333");

        System.out.println(vc);

    }

    public static void functioncall(java.util.Vector vc){

        vc.removeAllElements();  

    }
}

【问题讨论】:

  • 为什么要投反对票??不明白..
  • 我很想对代码缩进的“狗的早餐”投反对票,但让它滑倒吧。我怀疑它被认为有很多重复的人投了反对票。现在添加了pass-by-referencepass-by-value 标签,检查右侧栏中显示的“相关”线程以获得更好的点击率。
  • 因为它已经被询问了一百万次,搜索引擎很快就会显示出来。现在又会有无休止的辩论,因为大多数人都错误地认为这是通过引用来调用的。如果它是通过引用调用的,那么您的第一个示例将抛出 NullPointerException。
  • 向量只是一个数字的容器。所以在你的第一个例子中,函数 functioncall() 只是将变量 vc 设置为 null,但容器本身仍然存在于 main 中。在第二个函数中,您告诉容器自己清空。它仍然是同一个容器,并且没有制作竞争副本。 Java 总是按值传递,从不按引用传递。

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


【解决方案1】:

在java中按值传递意味着传递要传递的值的副本。在java中通过引用传递意味着传递地址本身。在 Java 中,参数总是按值传递。 Java 只支持传值。

对于 Java 对象,对象引用本身是按值传递的,因此原始引用和参数副本都引用同一个 Java 对象。 Java 原语也是按值传递的。

【讨论】:

    【解决方案2】:

    Java 编程语言总是使用按值调用。在Java中,方法的所有参数都是按值调用或按值传递的。 Cay S. Horstmann 和 Garry Cornell 在他们非常著名的书“Core Java Volume - I Fundamentals”中提到 Java 编程语言总是使用按值调用。这意味着该方法获取所有参数值的副本,并且该方法不能修改传递给它的任何参数变量的内容。 Java使用两种方法参数:

    • Java 原始类型
    • Java 对象引用

    当您尝试将原始类型传递给方法时,它看起来非常直接和简单,但在将对象传递给方法时变得晦涩难懂。有趣的是,当一个对象引用被传递给一个方法时,该方法得到一个对象引用的副本,并且原始副本和正式副本都引用同一个对象,因此在方法内可以更改对象参数的状态.

    下面的文章解释得很好Call by value and call by reference

    【讨论】:

      【解决方案3】:

      Java 和 C总是按值调用。引用调用这个术语严格适用于 C++,我们在形式参数中使用 & 运算符。在对象引用的情况下,引用会从实际参数复制到形式参数。

      【讨论】:

        【解决方案4】:

        按值传递

        实际参数(或参数表达式)被完全评估,结果值被复制到用于在方法/函数执行期间保存形式参数值的位置。该位置通常是应用程序运行时堆栈上的一块内存(这是 Java 处理它的方式),但其他语言可以选择不同的参数存储。

        引用传递 形参仅充当实参的别名。每当方法/函数使用形式参数(用于读取或写入)时,它实际上是在使用实际参数。 Java 是严格按值传递的

        【讨论】:

          【解决方案5】:

          Java 使用“按值调用概念”。如果它的堆栈和堆是可视化的,那么 java 会尝试在本地工作空间中查找任何变量的值,如果在本地没有找到,那么它会尝试在堆中的对象中查找。

          示例

          class Foo
          {
          
          int x;
          
          public void call(int x)
          
          {
          
              x++;
          
          }
          
          public static void main(String[] args)
          
          {
          
                 Foo foo = new Foo();
          
                 foo.x = 5;
          
                 System.out.println(foo.x);
          
                 foo.call(foo.x);
          
                 System.out.println(foo.x); 
          
          
          }
          
          
          }
          

          上述程序的输出将是 : 5 , 5 说明: 在 main 方法中,x 的值在 "foo: 在调用方法中,工作区中有一个名为“x”的局部变量(作为参数传递)。 所以它的值只会在它的工作区中改变。当此函数的控制返回到 main 方法时。在 main 的工作区中,“x”的值仍然是 5。

          示例

          class Foo
          
          {
          
          int x;
          
          public void call(int y)
          
          {
          
              x++;
          
          }
          
          public static void main(String[] args)
          
          {
          
                 Foo foo = new Foo();
          
                 foo.x = 5;
          
                 System.out.println(foo.x);
          
                 foo.call(foo.x);
          
                 System.out.println(foo.x); 
          
          }
          
          
          }
          

          上述程序的输出将是: 5 , 6

          说明: 在 main 方法中,x 的值在 "foo: 在调用方法中,工作空间中没有名为“x”的局部变量(作为参数传递)。所以java在引用中找到它,通过哪个“call”函数被调用并且“x”的值是5,call方法将它的值增加到“6” 因此它的值将被更改参考,即“foo”。当此函数的控制返回到 main 方法时。现在在 main 的工作区中,“x”的值是 6,因为这里我们在 foo 引用上打印了“x”。

          我希望这能帮助你理清概念。

          问候, 苏希尔耆那教

          【讨论】:

            【解决方案6】:

            使用Java“按引用传递”,引用本身是按值传递的。

            因此,您不能更改引用本身,但可以更改引用指向的对象。

            所以您的removeAll 调用作用于Vector,因此您可以看到结果。但是,如果您更改引用本身,例如:

            vc = null
            

            或者,

            vc = new Vector();
            

            这些更改指向一个新的(或 null )对象,因此之后的任何更改都不会反映在 main 中的对象中

            【讨论】:

            • “像往常一样通过引用传递......” 这根本不是“通过引用传递”的意思。这就是按值传递。在真正的传递引用中,例如在 C++ 中,您可以将变量传递给函数,并且函数可以将变量分配给该变量就像它是在调用范围内分配的。这是通过引用传递的“像往常一样”,在 Java 中是不可能的。
            • @user102008 好的.. 我编辑了它。你说得对……我的回答听起来像是在谈论所有语言。
            【解决方案7】:

            它是按值调用。在这两种情况下,您都将引用的 value 放在方法的参数中,即方法的 local 引用。

            【讨论】:

              【解决方案8】:

              您将 vc 作为参考副本传递(始终)。 然后做 vc = null;vc = new Vector(),你只是修改了vc本地属性的引用,所以main没有改变是正常的。

              【讨论】:

                【解决方案9】:

                它传递引用的

                为了厚颜无耻地盗用我刚才在这里看到的一个类比,假设您使用的每个标识符都是一张写有地址的纸。地址指向一所房子。

                您可以更改房子(例如,通过向矢量添加对象或清除它),但您仍然拿着同一张纸,地址仍然会将您带到同一个房子。

                如果你将向量设置为空,你所做的只是擦掉地址。

                This article 更详细地解释了它。

                【讨论】:

                  【解决方案10】:

                  vc 是一个新变量,其中包含用于调用该方法的向量的引用。将其更改为 null 不会影响原始向量,因为此引用是原始向量引用的副本。

                  但是由于这是对原始向量的引用,因此对向量的任何修改实际上都会改变原始向量。所以java总是使用按值调用,这里的值恰好是一个引用。

                  【讨论】:

                    【解决方案11】:

                    Java 使用对象引用。参数是参考值。 所以它是按值调用,其中值是对象的引用。

                    【讨论】:

                      猜你喜欢
                      • 2013-01-21
                      • 2016-11-28
                      相关资源
                      最近更新 更多