【问题标题】:Updating one list also updating referenced list in Java [duplicate]更新一个列表也会更新 Java 中的引用列表 [重复]
【发布时间】:2021-02-05 14:35:25
【问题描述】:

我遇到了奇怪的问题(至少对我来说很尴尬)。我有一个自定义对象列表。我正在添加这个自定义对象列表 2 个其他 ArrayLists。这是问题所在,当我更新列表之一(任何自定义对象的属性)时,它会更新其他列表中相同位置的对象。下面是代码

下面是自定义类的例子:

public class TestClass {
    String name;
}

这是我创建数据集的方式:

                    TestClass testClass1 = new TestClass();
                    testClass1.name= "first";

                    TestClass testClass2 = new TestClass();
                    testClass2.name= "second";

                    List<TestClass> data = new ArrayList<>();
                    data.add(testClass1);
                    data.add(testClass2);

这是我在其他 2 个列表中添加数据集的方式:

                    List<TestClass> testListFirst = new ArrayList<>();
                    testListFirst.addAll(data);

                    List<TestClass> testListSecond = new ArrayList<>();
                    testListSecond.addAll(data);

当我更新一个列表中的一个元素时,它也会在第二个列表中更新:

testListFirst.get(0).name = "third";

如果我检查 testListFirst 它会更新为新值,但 testListSecond 也会更新。我的期望是 testListSecond 它不应该被更新,因为它们都列出了内存中指向不同对象的不同对象。如果我更新另一个不应该更新。如果我错了,请纠正我。非常感谢任何帮助。

【问题讨论】:

  • 因为这里的对象是以引用方式调用的。

标签: java


【解决方案1】:

最好简单地提供一个新对象,而不是更改现有对象上的字段。然后,您将避免遇到的问题。我用构造函数修改了你的类来取名字。

TestClass testClass1 = new TestClass("first");
TestClass testClass2 = new TestClass("second");

List<TestClass> data = new ArrayList<>();
data.add(testClass1);
data.add(testClass2);

System.out.println("data = " + data);

List<TestClass> testListFirst = new ArrayList<>();
testListFirst.addAll(data);

List<TestClass> testListSecond = new ArrayList<>();
testListSecond.addAll(data);
System.out.println("Before adding 'third`");        
System.out.println("testListFirst = " + testListFirst);
System.out.println("testListSecond = " + testListSecond);
    
testListFirst.set(0, new TestClass("third"));
System.out.println("after adding 'third'");
System.out.println("testListFirst = " + testListFirst);
System.out.println("testListSecond = " + testListSecond);

打印


data = [first, second]
Before adding 'third`
testListFirst = [first, second]
testListSecond = [first, second]
after adding 'third'
testListFirst = [third, second]
testListSecond = [first, second]

你修改后的班级

class TestClass {
    public String name;
    public TestClass(String name) {
        this.name = name;
    }
    public String toString() {
        return name;
    }
}

【讨论】:

    【解决方案2】:

    这里的问题是您正在创建两个单独的列表,这是真的。但是列表中的对象是相同的。 因此,一旦您通过从任何列表中检索对象进行一些更改,它将更新同一对象的状态。

    示例解决方案:

    方法一:[推荐]

    List<TestClass> clonedist == new ArrayList<>(); //To store the clones
                
    for (TestClass temp : originalList){ //Looping through the original list and cloning the each element
         clonedList.add(new TestClass(temp.getName()));//Creating a new TestClass object and adding to the list.Name will be set to the object through it's overloaded constructor. 
    }  
    

    注意:这里将通过TestClass的重载构造函数创建新的TestClass对象。简而言之,我没有包含有关更新的 TestClass 的代码。但是您仍然可以创建新对象并通过其相关的 setter 方法或直接调用属性名称来更新它的状态(就像在您的代码 sn-p 中,如果访问修饰符的属性允许)。

    方法二:[clone()方法可能有问题]

    有关 clone() 方法的更多详细信息:Should I use Clone method in java?

    List<TestClass> clonedist == new ArrayList<>(); //To store the clones
                
    for (TestClass temp : originalList){ //Looping through the original list and cloning the each element
         clonedList.add(temp.clone());//cloning the object and adding to the list
    }  
    

    【讨论】:

    • 我期待通过引用传递的 ArrayList 但这是有道理的,自定义对象也是通过引用传递的。
    • 建议您远离clone,因为根据 Joshua Bloch 的说法,它已严重损坏。
    • 我也同意@WJS
    【解决方案3】:

    列表是不同的对象,但列表中的元素是相同的。您必须为每个列表的每个元素制作一个副本。

    【讨论】:

      猜你喜欢
      • 2021-05-20
      • 2015-06-29
      • 2022-01-02
      • 1970-01-01
      • 2017-02-02
      相关资源
      最近更新 更多