-2

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= "first";

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

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

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

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

                    List<TestClass> testListSecond = new ArrayList<>();
                    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 = "third";

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.

Abdul Waheed
  • 4,540
  • 6
  • 35
  • 58

3 Answers3

3

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

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 :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
}  
Hasindu Dahanayake
  • 1,344
  • 2
  • 14
  • 37
2

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

Prints


data = [first, second]
Before adding 'third`
testListFirst = [first, second]
testListSecond = [first, second]
after adding 'third'
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;
    }
}
WJS
  • 36,363
  • 4
  • 24
  • 39
1

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.

Thomas
  • 401
  • 1
  • 6
  • 11