Initial list gettign modified if duplicate list is modified - java

My problem is I have an initial list called currentComponents. I am copying it's items in another new list called currentMonitorComponents. But when the components in currentMonitorComponents are modified automatically the items in currentComponents list are also modified. My code is something like this ---
List<MonitorComponent> currentMonitorComponents = new ArrayList<MonitorComponent>();
currentMonitorComponents.addAll(currentComponents);

You have to make a deep copy of your list:
ArrayList<MonitorComponent> currentComponentsClone = new ArrayList<MonitorComponent>();
for(MonitorComponent m : currentMonitorComponents)
currentComponentsClone.add(m.clone());
And to implement clone method in your class:
public class MonitorComponent{
String s;
Date d;
...
public MonitorComponent clone(){
MonitorComponent m = new MonitorComponent();
m.s = this.s.clone();
m.d = this.d.clone();
...
return m;
}
}

at the end these both have same elements(MonitorComponent).. they are pointing to same objects in memory.. You have to make clone of every MonitorComponent inside the list..
You will need to iterate on the items, and clone them one by one, putting the clones in your result arraylist as you go.
public static List<MonitorComponent> cloneList(List<MonitorComponent> list) {
List<MonitorComponent> clone = new ArrayList<MonitorComponent>(list.size());
for(MonitorComponent item: list) clone.add(item.clone());
return clone;
}
For that to work, obviously, you will have to get your MonitorComponent object to implement the Cloneable interface, and the clone() method.

What you are doing is creating a shallow copy. You have a new list, but the elements are the same objects, not copies of the objects. So if you modify one of the objects you can see the changes via both lists.
You could alternatively make a deep(er) copy, by creating new objects for your new list which are copies of the objects from the first list. The exact you'd do this will depend on the type of objects in question. One option may be to use clone(). Another might be to invoke a copying constructor. You'd need to do this for each element of the origina list, and add the copy to your new list.

When you "copy" elements from the original list to the new list, you're really copying the references contained in the original list, not the actual objects in the original list. Thus, the first element in each list really points at the same underlying object; thus, when you change that object using one list, the other list sees the change. It's sort of like having two "views" of the same underlying series of objects.
To fix this, you need to "clone" each of the objects you want to copy from the original list. There are a few ways of doing this, but in the end you have to be sure that at some point in your code the new keyword is used, clone() is called (the clone() method in Java, from what I've been told, though, should be avoided), or a constructor is called. That ensures that the objects you're putting into the second list are distinct from the originals.

Related

Return list or modify by reference

In java, I have a method which is modifying the contents of a list. Is it better to use:
public List modifyList(List originalList) { // note - my real method uses generics
// iterate over originalList and modify elements
return originalList;
}
Or is it better to do the following:
public void modifyList(List originalList) {
// iterate over originalList and modify elements
// since java objects are handled by reference, the originalList will be modified
// even though the originalList is not explicitly returned by the method
}
Note - The only difference between the two methods is the return type (one function returns void and the other returns a List).
It all depends on how you are using your List - if you are implementing some kind of list and this is the non-static method of your List class, then you should write
public List modifyList() // returning list
or
public int modifyList() // number of elements changed
If it's method outside this class
About performing operations on List or its copy: you should consider desired bahaviour and your expectations - the most importantly - do I need "old" list copy?. Deep copying list can be a little overhead. Shallow copy will unable you to perform operations on certain elements of list (i.e. changing it's attributes - if they are objects) without affecting the "old" list.
About returning void: it's good practise to return changed list (or at least number of changed elements) which will allow you to chain methods invocations, if not needed you can always ignore it.
If you are just manipulating the list, it entirely depends on temperament. Some people(including me) would argue is easier to read code using the first option (and it allows for chaining as pointed out by Adam, if you want that sort of thing).
However, keep in mind that its not really a reference being passed in. Its a pointer really. Hence, if you reinitialize the originalList instance for some reason, as in putting a
originalList = new ArrayList();
in your method body. This will not affect the list you actually passed into the method.
In my opinion you should only encourage method chaining with immutable classes.
If your function mutates an object it is too easy to do it accidentally if in a chain of methods.
One possible benefit of Option 1 is that it can accept a null List. For example, if you are collecting Foos, and generally create a brand new List, but want the option to add to an existing list. e.g. (note name of method as well)
public List<Foo> appendFoos(List<Foo> in) {
if (in == null)
in = new ArrayList<Foo>;
// now go do it, e.g.
in.add(someFooIFound);
return in;
}
and, if you wish, add an explicit no-arg "get" method as well
public List<Foo> getFoos() {
return appendFoos(null);
}
Now, in Option #2, you could do this by having the user create a new, empty ArrayList and passing that in, but Option #1 is more convenient. i.e.
Option 1 Usage:
List<Foo> theFoos = getFoos();
Option 2 Usage:
List<Foo> theFoos = new ArrayList<Foo>();
appendFoos(theFoos);
As List is mutable, so second method is better. You don't need to return modified List.

Copying an ArrayList

I have an ArrayList of generic object type, i.e. List queue. I want to write a function EnqueueModified, that takes an arraylist and a list object as input and returns another ArrayList that contains the elments of the old arraylist and the list object but without affecting the original arraylist passed. i.e. Enqueue operation should be performed on a new copy of the arraylist and returned.
This can be done as follows:
public List<E> EnqueueModified(E e, List<E> queue) {
List<E> clone = new ArrayList<E>(queue);
clone.add(e);
return clone;
}
but is there a better method to do this? instead of using a copy constructor, is there any faster way to create a copy of the list? I cannot use cloning as it does not support for generic List.
To copy a list, you have to create a new list and fill it with items from the old list.
The constructor you are using might not actually be the best option, though. If you check the source code (google arraylist source code) you notice that it creates an array that is exactly as big as there are elements in the old collection.
Then it adds an element to that array. Because the array is too small, it has to create another copy of the array, only a bit bigger, and move the elements there again.
You could get a better performance by using
clone = new ArrayList(queue.size() + 1);
clone.addAll(queue);
clone.add(e);
Also, method names should start with a lower case letter. So use: enqueueModified(...)

Storing an Object into a temporary Object and not changing the original Objects value

I have an object stored in a global variable let's say:
static ArrayList<Object> list = new ArrayList<Object>();
I want to store it later to look into it without actually changing the values in the structure itself. So I am doing something similar to this:
public void someMethod()
{
ArrayList<Object> tempList = new ArrayList<Object>();
tempList = list;
list.remove(0);
}
I'm thinking this may have something to do with me initializing the variable as "static". I don't usually do that but Eclipse told me I had to so I just let the change happen.
My understanding would be that I am storing the original list into a temporary list and anything I do to the temporary list would be independent of the original list. But it appears that if I were to remove something from this above list, that the original list is removing it as well.
I remember learning that this could happen sometimes but I think I've done this before without having that issue.
I apologize if this is a repeated question but the way I worded it didn't show me an question that was similar.
Thanks!
My understanding would be that I am storing the original list into a temporary list and anything I do to the temporary list would be independent of the original list.
This is not the case. When you do something like
a = b;
then both a and b refer to the same object. Mutations in a show up in b and vice verse (since there is only a single object in question). In this case you probably want to use the copy constructor of ArrayList:
ArrayList<Object> tempList = new ArrayList<Object>(list);
Notice that here we are explicitly creating a new, independent object and assigning that to tempList.
Note that this creates what's called a shallow copy: the objects referenced by the list themselves are not copied, but instead a new list is created that contains the references to the same objects as the original list.
At the end of your someMethod, your tempList disappears into the dark void of the GC. If you want to keep it, you need to turn it into a similar field as list is.
Also, assigning list to tempList makes you have two references to the same object.

java list cannot add class then alter original class without altering the copy from the list

So i mostly program in C++, and java is very similar to c++.
I have created a list command as such
List<Item> stuff =new ArrayList<Item>();
where Item is a custom class that basically stores data.
I get information from a text file and store it to Item.
Then i use stuff.add to get the item class to stuff.
Afterwards i use a command to erase all data from the item class and see that it has also deleted all the data from the list.
Basically I want to know if there is a way to add a copy of the class and not the address of the class itself.
Edit:
so i found that reinitializing the item class also solved my problem thanks though.
You want to clone the item before adding it to the list. The list just has a reference to the original item that you created. As such, when you mutate your item, the item in the list is also affected (it's the same object).
If you want to "disconnect" the item that you put into your list, then you can clone it first. Your item class will need to implement Cloneable and override the clone() method. If you have only primitives in Item, then you can simply do:
public Object clone()
{
return super.clone();
}
If you have other objects in Item, then the default clone operation will only make a shallow copy, and you will need to make your clone method more extensive so that it makes deep copies. From the Javadoc for Object.clone():
By convention, the object returned by this method should be independent of this object (which is being cloned). To achieve this independence, it may be necessary to modify one or more fields of the object returned by super.clone before returning it. Typically, this means copying any mutable objects that comprise the internal "deep structure" of the object being cloned and replacing the references to these objects with references to the copies. If a class contains only primitive fields or references to immutable objects, then it is usually the case that no fields in the object returned by super.clone need to be modified.
In Java, objects references act like pointers in C++. There is no notion of "copy constructor". You have noticed this when you've added something to a list and then change the item after adding it to a list.
Generally in Java you will use new to create a new Item every time you add a new one to the list. So something like:
while (...) {
Item i = new Item(...);
stuff.add(i);
}
rather than
Item i = new Item();
while (...) {
i.foo = ...;
stuff.add(i);
}
The second example above will add the same object to the list multiple times.

How to make a separated copy of an ArrayList? [duplicate]

This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
Java: how to clone ArrayList but also clone its items?
I have a sample program like the following:
ArrayList<Invoice> orginalInvoice = new ArrayList<Invoice>();
//add some items into it here
ArrayList<Invoice> copiedInvoice = new ArrayList<Invoice>();
copiedInvoice.addAll(orginalInvoice);
I thought I can modify items inside the copiedInvoice and it will not affect these items inside originalInoice. But I was wrong.
How can I make a separated copy / clone of an ArrayList?
Thanks
Yes that's correct - You need to implement clone() (or another suitable mechanism for copying your object, as clone() is considered "broken" by many programmers). Your clone() method should perform a deep copy of all mutable fields within your object. That way, modifications to the cloned object will not affect the original.
In your example code you're creating a second ArrayList and populating it with references to the same objects, which is why changes to the object are visible from both Lists. With the clone approach your code would look like:
List<Foo> originalList = ...;
// Create new List with same capacity as original (for efficiency).
List<Foo> copy = new ArrayList<Foo>(originalList.size());
for (Foo foo: originalList) {
copy.add((Foo)foo.clone());
}
EDIT: To clarify, the above code is performing a deep copy of the original List whereby the new List contains references to copies of the original objects. This contrasts to calling ArrayList.clone(), which performs a shallow copy of the List. In this context a shallow copy creates a new List instance but containing references to the original objects.
If you are storing mutable objects into the ArrayList, you will need to copy each object when you copy the ArrayList. Otherwise, the new ArrayList will still hold the original references.
However if you're storing immutable objects, it's fine to use:
ArrayList copiedInvoice = new ArrayList(originalInvoice);
I thought I can modify items inside the copiedInvoice and it will not affect these itmes inside originalInoice.
This happens because what gets copied is the reference variable and not the object it self.
Hence you end up with two "references" pointing to the same object.
If you need to copy the whole object you may need to clone it.
But you might have problems if you don't clone the object internal attributes if they happen to be other objects.
For instance the following class definition won't give you any problem.
public class Something {
private int x;
private int y;
private String stringObject;
}
If you create a copy of that, you would copy the current values of its attributes and that's it.
But if your class do have another object inside you might consider to clone it too.
class OtherSomething {
Something something;
private int x;
}
If you do the following:
Something shared = new Something();
OtherSomething one = new OtherSomething();
OtherSomething two = new OtherSomething();
one.something = shared;
two.something = shared;
In this case, both one and two have the same reference variable to the same shared "something" and changing the value in one would affect the other.
That's why it is much simpler/better/easier to use immutable objects.
If you need to change the value of an immutable object you just create a new one with the correct value.
Take a look at ByteArrayOutputStream and ByteArrayInputStream. If all of your classes implement Serializable, then you can make a copy using the above mentioned classes.

Categories