Java - 按值传递:为什么列表在移交给另一个class时会发生变化?

Java - Pass by value: Why does the list change when being handed over to another class?

我正在为我的学校做一个 Java 问题,它给了我这个实用程序 class:

import java.util.*;

public class PassByValue
{

    private PassByValue() {}

    public static void add(int a)
    {
        a = a + 1;
    }

    public static void add(Set<String> b)
    {
        b = new HashSet<String>();
        b.add("ABC");
    }

    public static void add(List<Integer> c)
    {
        c.add(new Integer(1));
    }
}

它也给了我这个 class 和 main 方法

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class PassByValueClient
{
    public static void main(String[] args)
    {
        PrintStream output = System.out;

        int a = 1;
        PassByValue.add(a);
        output.println(a);

        Set<String> b = new HashSet<String>();
        PassByValue.add(b);
        output.println(b.size());

        List<Integer> c = new ArrayList<Integer>();
        PassByValue.add(c);
        output.println(c.size());
    }
}

我们应该预测输出。当我预测输出结果时,我的猜测分别是 100。但是,当我 运行 代码时,我得到的输出分别是 101。根据我对将 parameters/arguments 传递给方法的理解,客户端的代码应该保持不变。有人能告诉我为什么输出是 1 而不是 0 吗?

这是因为移交给 PassByValue.add() 的列表指向您存储中的一个位置(地址),即列表的位置(例如地址 42)。而当列表在方法.add()中时,它仍然指向同一个地址(42)

如果您更改它,该地址 (42) 上的数据也会更改。但是两个列表仍然指向相同的地址(42),所以它们指向相同的数据。

我想用图片解释你的例子中发生了什么:

/////////////////////////////////////////// //////////////////////////////////////////////// //////////////////////////////////////////////// ///////// 变量"a"

Integer a = 1

这会在您的存储中创建一个地址,变量 a 指向该地址:

然后将其传递给方法时 PassByValue.add(a) 会创建一个新变量。但是这个新变量指向相同的地址(值)。

当您用 a = a+1 更改它时,变量不再指向地址,而是指向一个新地址,具有新值。

/////////////////////////////////////////// //////////////////////////////////////////////// //////////////////////////////////////////////// ///////// 变量"b"

当您声明它时,会创建一个指向特定地址的对象:

当你移交它时,会创建另一个指向相同地址的对象:

当你将PassByValue.add()中的对象设置为= new HashSet<String>();时,它指向另一个地址。

//////////////////////////////////////////////// //////////////////////////////////////////////// //////////////////////////////////////////////// //// 变量"c"

当您更改对象本身时,情况就不同了。

就像你对列表所做的那样。 通过创建列表 List<Integer> c = new ArrayList<>(); 变量指向特定地址。

当你把它交给.add()-方法时,一个新变量被创建,但它指向相同的地址。

然后当您通过说 c.add(new Integer(1)); 来更改它时,您更改了对象本身。当您更改对象 ITSELF 时,存储在该地址上的数据会更改,但不会创建新的 address-space 并且两个变量仍指向同一地址。