Hafiz Temuri
Hafiz Temuri

Reputation: 4112

Adding List Objects into Another List in JAVA

Let's say I have three Lists free, home and tableau, they all contains different objects. I also have a class called History and its constructor takes all these three lists and makes a new Object. Now, I am trying to make a List<History> that contains all the history objects. I am adding all the <History> objects as follows,

List<Hisotry> history = new ArrayList<>();
history.add(new History(free, home, tableau));

//make some changes in the lists (free, home, tableau),
//then add it again in the history list
history.add(new History(free, home, tableau));

//make some more changes again then add it
history.add(new History(free, home, tableau));

Although it's adding all the objects into the list, but they all referring to the same object. In other words, if I add 3 <History> objects, it prints the same <Hisotry> object 3 times, when they all should be different. I am not sure why it's adding or referring to the same object when each time I create a new object and add it to the list. What am I doing wrong while adding new objects?

**P.S. I hope I am making sense, if not, please feel free to let me know and I will upload my whole code.

Upvotes: 3

Views: 4326

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 338316

The Answer by Shesterov is correct.

Here is a diagram to show what you have as described in the Question. I added "Animal" objects as the elements contained in your "free"-"home"-"tableau" lists as you did not mention their contents.

enter image description here

That correct answer was making two points:

  • All three "History" objects point to the very same 3 lists named "free", "home", and "tableau". If you add an item to "home" list or drop an item from "tableau" list, all three "History" objects will see the changes. If you want each History object to have its own private collection of "Animal" objects, then copy the lists in the constructor of History. One way of copying the lists is to instantiate a new List and feeding the old list to its constructor.
  • If you mutate (change the member fields) in any Animal object, any other object anywhere in this hierarchy will see the change if it holds a reference (pointer) to that particular Animal object. So change the cat named "John" to have a name of "Pierre", and both the "home" & "tableau" lists (but not "free" list) as well as all three History objects will all be affected as their can named John is now known as Pierre.

If you followed Shesterov’s code and duplicated each list during each History object’s construction, you would end up with 12 pink lists rather than 3: the original 3 plus 3 lists for each of the 3 History objects. So: 12 = 3 + ( 3 * 3 ). But you still have the same 5 Animal objects. But going this route History "b", for example, could alter its "home" list to drop the reference to the bird named Bob while the original "home" list and the History "a" "home" list and the History "c" "home" list would still each have a pointer reference to the bird named Bob.

In other words, do not think of passing object references as going through a Xerox machine. Instead think of these objects as paper index cards, each connected as seen in this diagram by a string with Scotch tape attaching the string to the card. Passing an object does not xerox the card; passing an object attaches another string with tape.

One last point: Do not confuse a List/Collection object with the elements it "contains" (points to). In a warehouse, you may take an inventory of crates by listing the ID number of each crate on a clipboard. The clipboard is a "List" but is not itself the crates. The clipboard/inventory object is a collection that refers to completely separate distinct other objects, the crates.

Upvotes: 2

i-bob
i-bob

Reputation: 423

You are creating new History object each time, which is fine. But you said you are modified existing free, home and tableau array lists. These 3 arrays lists are still being modified using the same reference and therefore you are updating them in the other History objects as well.

Upvotes: 1

Alex Shesterov
Alex Shesterov

Reputation: 27525

You've already correctly figured out that the History objects hold references to the same lists. Thus, you have 3 different History objects, but all of the 3 instances "point" to the same lists.

You could clone the lists before modifying them for a new History object, i.e.:

List<History> history = new ArrayList<>();
history.add(new History(free, home, tableau));

free = new ArrayList(free);
home = new ArrayList(home);
tableau = new ArrayList(tableau);
// make some changes to the lists
history.add(new History(free, home, tableau));

free = new ArrayList(free);
home = new ArrayList(home);
tableau = new ArrayList(tableau);
// make more changes to the lists
history.add(new History(free, home, tableau));

Please note that if the lists free, home, tableau hold references to mutable objects, and these objects can be changed according to your program logic, then the above code won't work and you will need to clone every list item as well.

Upvotes: 2

Related Questions