【问题标题】:What does Pass Reference by Value in Java mean?Java中按值传递引用是什么意思?
【发布时间】:2014-07-14 18:06:19
【问题描述】:

我在网站上研究 Java 参数时经常看到这种情况,但我认为我误解了它。

问题一:Is Java "pass-by-reference" or "pass-by-value"?

问题2:Does Java pass by reference?

人们一直说在java中引用类型是按值传递的,所以引用本身不会改变。而且我相信我的困惑来自“引用本身”是什么。

最初我将其解释为参数所指的内容不能以任何方式更改或修改,例如将某些内容添加到列表中。遗憾的是,这在某种程度上是错误的,并导致了有趣的结果。

当我运行下面的简单代码时,我得到了[test1, test2],所以在我看来“参考”list 发生了变化。

import java.util.ArrayList;
import java.util.List;

public class HelloWorld {
    public static void main(String[] args)
    {
        List list = new ArrayList();
        list.add("test1");
        breakStuff(list);
        System.out.println(list.toString());
    }

    public static void breakStuff( List l ) {
        l.add("test2");
    }
}

根据我目前对人们的意思的“想法”(Question 1 的答案),随着事情的变化,他们是错误的。我没有理解或忽略什么?

人们是否指的是您可以修改参数所引用的数据,但您不能更改参数所指的“数据/对象”?

【问题讨论】:

  • 您可以更改引用的对象,但不能更改引用。
  • 你可以mutate一个对象,如果它是可变的(并且ArrayList是可变的),但是你不能让调用者中的变量引用不同的@987654328 @。传递引用的严峻考验是您是否可以编写一个swap(Object a, Object b) 方法,该方法将在调用者中切换ab。顺便说一句,你不应该使用原始类型 ListArrayList,而应该使用 List<String>ArrayList<String>
  • 这有 got 是重复的!!超过 100 次。
  • Java 中的“引用”具有特定 的含义,本质上与C 中的“指针”相同。引用是在参数列表中传递的内容。被调用者不能以调用者可见的方式更改它们(因为它们是“按值”传递的)。这与在例如教科书中使用术语“参考”不同,其中“参考”本质上是一些外部实体(例如另一本书)。
  • @PeterLawrey 感谢您一起解释双方。最初,当我在链接的问题中阅读“您可以更改引用的对象”时,我认为它们的意思是更改引用的对象,只是稍后在答案中告诉我不能。希望我现在能更好地理解术语:)

标签: java pass-by-reference


【解决方案1】:
public class HelloWorld {
    public static void main(String[] args)
    {
        List list = new ArrayList(); // here list is a "reference" to an "ArrayList" Object
        list.add("test1"); // adding data to the "Object" using the "reference"
        breakStuff(list); // passing the "reference-by-value"
        System.out.println(list.toString()); // printing
    }

    public static void breakStuff( List l ) { // getting the same reference as the original. So l==list is true.
        l.add("test2"); // adding to the same/original object because the reference is same.
l=null; // try this and see what happens. l will point to a "different" object i/e, null while list will be pointing to the original one.
    }
}

【讨论】:

    【解决方案2】:

    人们是否指的是您可以修改数据的事实? 参数正在引用,但您不能更改哪个“数据/对象” 论据指的是什么?

    是的,没错。例如:

    public class HelloWorld {
      public static void main(String[] args)
      {
        List list = new ArrayList();
        list.add("test1");
        breakStuff(list);
        System.out.println(list.toString());
      }
    
      public static void breakStuff( List l ) {
        l.add("test2");
        l = new ArrayList();
        l.add("foo");
      }
    }
    

    不会将原始list 更改为一个新列表,其中包含一个名为foo 的元素。这就是 按值传递引用的含义:如果您使引用的值副本引用一个新对象,则原始引用仍然引用相同的旧对象。 p>

    【讨论】:

    • 谢谢,原来的问题和答案的模棱两可误导了我。感谢您清除它:)
    【解决方案3】:

    意思是

    a = c ;
    f(a) { a = b; }
    // after we are out of f() here a == c
    

    然而

    a.x = 0
    f(a) { a.x = 1 }
    // after we are out of f() here a.x == 1
    

    【讨论】:

      【解决方案4】:

      引用指向一个对象。

      您没有更改引用,而是更改了对象。

      这会改变引用,但不会改变变量list,因为引用本身会被复制:

      public static void breakStuff( List l ) {
              l = new ArrayList();
      }
      

      【讨论】:

        【解决方案5】:

        这意味着当你通过值传递引用时,你可以改变它的值,但什么都不会发生。

        void passReferenceByValue(List list) {//Java code
        
            list = new ArrayList(); //We assign new value to reference
            list.add("reftByValue")'
        
        }
        void passReference(List* list) {//Non Java code
        
           list = new ArrayList(); //We assign new value to reference 
           list.add("reference")'
        }
        

        我们测试一下:

          void testPassing() {
        
            List start = null;
        
            passByValue(start);
        
            System.out.println("PassByValue: " + start);
        
            passReference(start);
        
            System.out.println("PassReference:" + start);
          }
        

        输出:

        PassByValue: null
        PassByValue: {reference}
        

        常见误解的原因是实例的变化而不是引用的变化。

           void mutationTest(List list) {
        
                 list.add("mutationOfList"); // In this case we mutate the object that reference point.
           }
        

        【讨论】:

          【解决方案6】:

          ArrayList 对象实际上是在堆上。 ArrayList 对象始终保持在堆上的位置。

          您的引用“列表”(List 类型)“指向”堆上的那个对象。或者换一种说法:“list”包含那个对象的内存地址!

          当您将该引用传递给另一个方法时 - 您正在传递该对象在堆上的位置。或者换一种说法:您将堆上(固定)对象的地址从一个方法传递到另一个方法。

          当breakstuff方法使用“l”引用时,它会修改“l”指向的对象。

          一个愚蠢但有意义的类比:你用一把魔法步枪瞄准你房子旁边山上的一只马鹿。然后,您将步枪寄给下一个城镇的朋友。当朋友通过步枪瞄准器查看时,步枪立即转向并指向那只马鹿所在的山丘。

          【讨论】:

            【解决方案7】:

            您熟悉另一种语言吗?比较会很有启发性。

            Java 代码:

            public class HelloWorld {
                public static void main(String[] args)
                {
                    List list = new ArrayList();
                    list.add("test1");
                    breakStuff(list);
                    System.out.println(list.toString());
                }
            
                public static void breakStuff( List l ) {
                    l.add("test2");
                }
            }
            

            等效的 C++:

            class HelloWorld {
            public:
                static void main(String[] args)
                {
                    List *list = new ArrayList();
                    list->add("test1");
                    breakStuff(list);
                    System::out->println(list->toString());
                }
            
                static void breakStuff( List *l ) {
                    l->add("test2");
                }
            }
            

            你会说在 C++ 中有通过引用传递吗?还是全部传值?

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-05-22
              • 2011-12-28
              • 2013-10-30
              • 2013-05-31
              • 2014-04-12
              • 2016-11-28
              相关资源
              最近更新 更多