Updating one list also updating referenced list in Java

huangapple go评论77阅读模式
英文:

Updating one list also updating referenced list in Java

问题

我面临着一个奇怪的问题(对我来说至少是很尴尬的)。我有一个自定义对象的列表。我将这个自定义对象的列表添加到另外两个ArrayList中。问题在于,当我更新其中一个列表(自定义对象的任何属性),它会更新另一个列表中相同位置的对象。以下是代码示例:

以下是自定义类的示例:

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

以下是我如何将数据集添加到另外两个列表中:

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

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

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

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

如果我检查testListFirst,它已经更新为新的值,但是testListSecond也被更新了。我原本的期望是testListSecond不应该被更新,因为它们两个在内存中是不同的对象,指向不同的对象。如果我更新一个对象,另一个对象不应该被更新。如果我理解错了,请纠正我。非常感谢您的帮助。

英文:

I am facing strange problem (At least awkward for me). I have a list of custom objects. I am adding this list of custom objects 2 other ArrayLists. Here is the problem, when I update one of the list (a property of any custom object), it updates the object of same location in other list. Below is the code

Below is the custom class for example:

public class TestClass {
    String name;
}

Here is how I am creating data set:

                    TestClass testClass1 = new TestClass();
                    testClass1.name= &quot;first&quot;;

                    TestClass testClass2 = new TestClass();
                    testClass2.name= &quot;second&quot;;

                    List&lt;TestClass&gt; data = new ArrayList&lt;&gt;();
                    data.add(testClass1);
                    data.add(testClass2);

Here is how I am adding data set in other 2 Lists:

                    List&lt;TestClass&gt; testListFirst = new ArrayList&lt;&gt;();
                    testListFirst.addAll(data);

                    List&lt;TestClass&gt; testListSecond = new ArrayList&lt;&gt;();
                    testListSecond.addAll(data);

Here is the problem when I update an element of one list it gets updated in second list as well:

testListFirst.get(0).name = &quot;third&quot;;

If I check testListFirst it is updated with new value, but testListSecond is also updated. My expectation was testListSecond It should not get updated because they both list are different object in memory pointing different objects. If I update one other should not be updated. Please correct me if I am wrong. Any help is highly appreciated.

答案1

得分: 3

问题在于你创建了两个独立的列表,这是正确的。但列表中的对象是相同的。因此,一旦你从任何列表中检索对象并进行更改,它将更新相同对象的状态。

样例解决方案:

方法1:[推荐]

List<TestClass> clonedList = new ArrayList<>(); //用于存储克隆对象
            
for (TestClass temp : originalList){ //遍历原始列表并克隆每个元素
     clonedList.add(new TestClass(temp.getName())); //创建一个新的 TestClass 对象并添加到列表中。通过它的重载构造函数设置 Name 属性。
}  

注意:这里通过 TestClass 的重载构造函数创建了新的 TestClass 对象。为了简洁起见,我没有包含关于更新后的 TestClass 的代码。但你仍然可以通过相关的 setter 方法创建新对象并更新其状态,或者直接调用属性名称(如果属性的访问修饰符允许的话)。

方法2:[clone() 方法可能存在问题]

有关 clone() 方法的更多详细信息:https://stackoverflow.com/questions/26578517/should-i-use-clone-method-in-java

List<TestClass> clonedList = new ArrayList<>(); //用于存储克隆对象
            
for (TestClass temp : originalList){ //遍历原始列表并克隆每个元素
     clonedList.add(temp.clone()); //克隆对象并添加到列表中
}  
英文:

The problem here is you are creating two separate lists, it's true. But the objects which are inside the lists are the same. So, once you do some change by retrieving an object from any list, it will update the state of the same object.

Sample Solutions:

Method 1:[Recommended]

List&lt;TestClass&gt; clonedist == new ArrayList&lt;&gt;(); //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&#39;s overloaded constructor. 
}  

Note:Here new TestClass object will be created through the overloaded constructor of the TestClass. To be brief I didn't include the codes regarding the updated TestClass.But you can still create the new object and update it's state through it's relevant setter methods or directly calling the attributes names(Like in your code snippet if the access modifier of the attribute allows).

Method 2:[There might be some issues with the clone() method ]

More Details regarding the clone() method :https://stackoverflow.com/questions/26578517/should-i-use-clone-method-in-java

List&lt;TestClass&gt; clonedist == new ArrayList&lt;&gt;(); //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
}  

答案2

得分: 2

不要改变现有对象上的字段,最好只是提供一个新对象。这样,您将避免遇到的问题。我已经修改了您的类,添加了一个带有名称参数的构造函数。

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("添加 'third' 之前");		
System.out.println("testListFirst = " + testListFirst);
System.out.println("testListSecond = " + testListSecond);
	
testListFirst.set(0, new TestClass("third"));
System.out.println("添加 'third' 之后");
System.out.println("testListFirst = " + testListFirst);
System.out.println("testListSecond = " + testListSecond);

打印结果

data = [first, second]
添加 'third' 之前
testListFirst = [first, second]
testListSecond = [first, second]
添加 'third' 之后
testListFirst = [third, second]
testListSecond = [first, second]

您修改过的类

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

Instead of changing fields on an existing object it is best to simply provide a new object. Then you will avoid the problem you are experiencing. I modified your class with a constructor to take a name.

TestClass testClass1 = new TestClass(&quot;first&quot;);
TestClass testClass2 = new TestClass(&quot;second&quot;);

List&lt;TestClass&gt; data = new ArrayList&lt;&gt;();
data.add(testClass1);
data.add(testClass2);

System.out.println(&quot;data = &quot; + data);

List&lt;TestClass&gt; testListFirst = new ArrayList&lt;&gt;();
testListFirst.addAll(data);

List&lt;TestClass&gt; testListSecond = new ArrayList&lt;&gt;();
testListSecond.addAll(data);
System.out.println(&quot;Before adding &#39;third`&quot;);		
System.out.println(&quot;testListFirst = &quot; + testListFirst);
System.out.println(&quot;testListSecond = &quot; + testListSecond);
	
testListFirst.set(0, new TestClass(&quot;third&quot;));
System.out.println(&quot;after adding &#39;third&#39;&quot;);
System.out.println(&quot;testListFirst = &quot; + testListFirst);
System.out.println(&quot;testListSecond = &quot; + testListSecond);

Prints


data = [first, second]
Before adding &#39;third`
testListFirst = [first, second]
testListSecond = [first, second]
after adding &#39;third&#39;
testListFirst = [third, second]
testListSecond = [first, second]

Your modified class

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

</details>



# 答案3
**得分**: 1

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

<details>
<summary>英文:</summary>

The lists are different objects, but the elements in the list are the same. You have to make a copy of each element for each list.

</details>



huangapple
  • 本文由 发表于 2020年10月22日 22:35:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/64484572.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定