简体   繁体   English

Java中的Pass引用值是什么意思?

[英]What does Pass Reference by Value in Java mean?

I keep seeing this when researching Java arguments on the site but I believe I am misunderstanding it. 我在网站上研究Java论点时一直看到这一点,但我相信我误解了它。

Question 1: Is Java "pass-by-reference" or "pass-by-value"? 问题1: Java是“通过引用传递”还是“按值传递”?

Question 2: Does Java pass by reference? 问题2: Java是否通过引用传递?

People keep saying that in java reference types are passed by value, so that the reference itself isn't changed. 人们一直说java引用类型是按值传递的,因此引用本身不会改变。 And I believe my confusion comes from what the "references itself" is. 而且我相信我的困惑来自于“引用本身”。

Originally I interpreted it to mean that what the argument was referring to, couldn't be changed or modified in any way, such as something being added to a list. 最初我将其解释为意味着参数所指的内容,无法以任何方式更改或修改,例如添加到列表中的内容。 Sadly this to some degree is wrong and has caused interesting results. 遗憾的是,这在某种程度上是错误的并且已经产生了有趣的结果

When I run the simple code below I get [test1, test2] , so in my mind "the reference" list got changed. 当我运行下面的简单代码时,我得到[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");
    }
}

With my current "idea" of what the people mean (answers to Question 1 ), they are wrong as things are changing. 根据我目前对人们意味着什么的“想法”( 问题1的答案),当事情发生变化时,他们错了。 What am I not understanding or overlooking? 我不理解或忽视什么?

Are the people referring to the fact that you can modify the data the argument is referencing, but you can't change which "data/object" the argument is referring to? 是否有人提到您可以修改参数引用的数据这一事实,但您无法更改参数所指的“数据/对象”?

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.
    }
}

Are the people referring to the fact that you can modify the data the argument is referencing, but you can't change which "data/object" the argument is referring to? 是否有人提到您可以修改参数引用的数据这一事实,但您无法更改参数所指的“数据/对象”?

Yes, exactly. 对,就是这样。 For example: 例如:

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");
  }
}

Does not change the original list to be a new list with a single element named foo . 不会将原始list更改为具有名为foo的单个元素的新列表。 This is what it meant by that the reference is passed by value : if you make the value copy of the reference refer to a new object, the original reference still refers to the same, old object. 这就是通过值传递引用的含义:如果使引用的值副本引用新对象,则原始引用仍引用相同的旧对象。

It means 它的意思是

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

However 然而

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

A reference points to an object. 引用指向对象。

You didn't change the reference but the object. 您没有更改引用而是更改对象。

This would change the reference, but it won't change the variable list because the reference itself gets copied: 这会改变引用,但它不会更改变量list因为引用本身会被复制:

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

What this mean is that when you pass reference by value you can change its value and nothing will happen. 这意味着当您通过值传递引用时,您可以更改其值,并且不会发生任何事情。

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")'
}

Wen we test it: 我们测试一下:

  void testPassing() {

    List start = null;

    passByValue(start);

    System.out.println("PassByValue: " + start);

    passReference(start);

    System.out.println("PassReference:" + start);
  }

The output: 输出:

PassByValue: null
PassByValue: {reference}

The reason of common misunderstanding is mutation of instance not change of the reference. 常见误解的原因是实例的变异而不是参考的变化。

   void mutationTest(List list) {

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

The ArrayList object is actually on the heap. ArrayList对象实际上在堆上。 The ArrayList object always stays where it is on the heap. ArrayList对象始终保持在堆上的位置。

Your reference "list" (of type List) is "pointing" to that object on the heap. 您的引用“list”(类型为List)是“指向”堆上的该对象。 Or said another way: "list" contains the memory address of that object! 或者说另一种方式:“list”包含该对象的内存地址!

When you pass that reference to another method - you are passing the location of that object on the heap. 将该引用传递给另一个方法时 - 您将在堆上传递该对象的位置。 Or said another way: you are passing the address of the (stationary) object on the heap from one method to another method. 或者换句话说:您将堆上(静止)对象的地址从一个方法传递到另一个方法。

When the breakstuff method uses the "l" reference it will modify the object that "l" points at. 当breakstuff方法使用“l”引用时,它将修改“l”指向的对象。

A stupid, but informing analogy: You aim a magic rifle at a red deer on the hill beside your house. 一个愚蠢的,但通知类比:你在你家旁边山上的一只红鹿瞄准一支魔术步枪。 You then post the rifle to a friend in the next town. 然后你将步枪发给下一个城镇的朋友。 When the friend looks through the rifle sight the rifle immediately turns and points to the hill with the that red deer. 当朋友透过步枪瞄准镜时,步枪立即转动并指向那只红鹿的山丘。

Are you familiar with another language? 你熟悉另一种语言吗? A comparison would be instructive. 比较将是有益的。

Java code: 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");
    }
}

equivalent C++: 等效的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");
    }
}

Would you say there is pass by reference here in the C++? 你会说在C ++中有引用传递吗? Or all pass by value? 或者全部通过价值?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM