Two java List objects having same reference? - java

I am using two java List objects that contain some data.
the first list contains all the data objects inside it and teh second one contains some of the data(not all) from the original list.
The original list itself is a static object that can be accessed .
Here is the code below that copies the whole contents of the original list into a new List and then ammends the copied list my removing certain elements.
The issue i am having is that it seems to effect and remove same elements from the Original list!
private List<Device> deviceList;
deviceList = App.devices;
//check which devices have not been added by checking the position data
for (Iterator<Device> iterator = deviceList.iterator(); iterator.hasNext(); ) {
Device device = iterator.next();
if (device.getPosition() != Device.NO_POSITION) {
iterator.remove();
}
}

In this line of code:
deviceList = App.devices;
you are not copying the list, but creating another reference to it.
To make a shallow copy of the list you can use for example: ArrayList constructor which accepts Collection as a parameter and makes copy.
So it should be like that:
private List<Device> deviceList = new ArrayList(App.devices);

deviceList = App.devices; does not create a new object but it just points on the App.devices object. You could use ArrayList deviceList = new ArrayList(App.devices). This one will instatiate a new object ArrayList and it will not effect your static list object.
However, keep in mind that any change on your object Device will be applied on both on your lists too, because both objects inside those two lists are pointing on the same adress. So if you want to apply individual changes to your objects inside your deviceList, you should create new Device objects as well. You might want to take a look at Deep and Shallow copy.

Related

Clone a list and modify the property of an element to list does not work in Java

I tried to make a clone of an arraylist so there will be two lists created. After that, I tried to modify the property of an element in one of the lists. When I compared the lists, it should have given me false for equal result but instead it is true. I assume this got to do with the pointer of the element or list. Is there any solution to fix that?
My code is like this:
List<UnifiedBucket> ubsCopy = new ArrayList<>(ubs);
ubsCopy.get(14).setRawPolicy(null);
UnifiedBucket ub1 = ubs.get(14);
UnifiedBucket ub2= ubsCopy.get(14);
System.out.println(ub1 == ub2);
System.out.println(ub1.getRawPolicy().equals(ub2.getRawPolicy()));
what you want to have is a deep copy but the constructor does shallow copy , look at public ArrayList(Collection c)
if you want to make a deep copy use Iterator on ArrayList like this :
List<UnifiedBucket> UnifiedBucketClone = new ArrayList<>();
Iterator<UnifiedBucket> iterator = ubs.iterator();
while(iterator.hasNext()){
UnifiedBucketClone .add((UnifiedBucket) iterator.next().clone());
}

ConcurrentModificationException at for each android

I am passing Arraylist of ParseObject, and then i am putting one one foreach loop to extract the items with a condition when user object is not equals to null. There are two problems which i am facing.
1. If i am doing the following lines of code by passing different data to another list and then pass that list in my adapter, i am getting random data with numbers for example: If on item # 1 the name is "MAC" then it is showing in item 3.
ArrayList<ParseObject> checkRequestedNetArrayList = new ArrayList<ParseObject>();
requestedNetArrayList = (ArrayList<ParseObject>) objects;
MyResponsibilitesActivity.requestedNetArrayList = requestedNetArrayList;
adapterRequest = new GenericAdapter<ParseObject>(
getApplicationContext(),
requestedNetArrayList,
R.layout.requested_trust_net_list_item,
requestedDataBinder);
requestListView.setAdapter(adapterRequest);
requestedNetArrayList = (ArrayList<ParseObject>) objects;
for(ParseObject object: objects){
System.out.println(object);
object.getParseObject("user");
if(object.has("user")){
checkRequestedNetArrayList.add(object);
}else{
checkRequestedNetArrayList.remove(object);
}
}
adapterRequest = new GenericAdapter<ParseObject>(
getApplicationContext(),
checkRequestedNetArrayList,
R.layout.requested_trust_net_list_item,
requestedDataBinder);
requestListView.setAdapter(adapterRequest);
If i am doing the following line of code to just direct giving the items in the same list, i am getting the java.util.ConcurrentModificationException
for(ParseObject object: objects){
if(object.has("user")){
requestedNetArrayList.add(object);
}
}
else{
requestedNetArrayList.remove(object);
}
adapterRequest = new GenericAdapter<ParseObject>(
getApplicationContext(),
requestedNetArrayList,
R.layout.requested_trust_net_list_item,
requestedDataBinder);
requestListView.setAdapter(adapterRequest);
}
Please help me out here.
You can not remove an element from list while accessing it.
You have to use Iterator.
Where ever you are removing the object, use it.remove();
Iterator<ParseObject> it = objects.iterator();
while(it.hasNext()){
Object object = it.next();
//your stuff
it.remove();
}
I think you might want to check this article about deep copy also.
UPDATE
Since you want to add elements to the list it is not directly possible with iterator. Now you are facing problem because you are directly assigning objects to requestedNetArrayList instead of that do it in the following way :
ArrayList<ParseObject> requestedNetArrayList = new ArrayList<>(objects);
Then iterate over objects as you are doing now, and remove from or add to
requestedNetArrayList (which you are pretty much already doing).
When you make iteration using for-each construction for Collection
for (Object x : collection) ...
you have implicit creation of Iterator object for that Collection. This iterator performs a check: is collection was changed since iterator was created? If so, throwing an exception. So, you should avoid to any modify to your collection, until iterator done. That means, you should not use add and remove.
In either way, it is better to access ArrayList by index, because it will prevent creation of Iterator object. Like this:
for (int i = objects.size() - 1; i >= 0; i--) {
ParseObject object = objects.get(i);
// when iterating from tail to head, you can safely add or remove objects to/from this array list
}
Instead of assigning the reference of objects to requestedNetArrayList,
create a new ArrayList with the same contents
requestedNetArrayList=new ArrayList<ParseObject>(objects);
Then you can iterate on objects and modify requestedNetArrayList.

How to create a copy of ArrayList<ArrayList<Arc>> to another ArrayList<ArrayList<Arc>>

I have a Class
public class Arc{
...
}
and 2 ArrayList
ArrayList<ArrayList<Arc>> rotalar1 = new ArrayList<ArrayList<Arc>>();
ArrayList<ArrayList<Arc>> rotalar2 = new ArrayList<ArrayList<Arc>>();
i try to copy rotalar1 to in rotalar2:
rotalar2.addAll(rotalar1);
but i have a problem. if i make any change in rotalar2 , it has an impact on rotalar1 too. I dont want to make a change in rotalar1 :
These rows make problem
rotalar2.get(random1).remove(random3);
rotalar2.get(random2).remove(random4);
Thanks for your time
Iterate over rotalar1 an copy each list of this list to rotalar2. You can make the copy in different ways. In the first example i use the constructor and create a new list with the same elements. Be careful, if you make changes to the Arc objects, this changes will still take effect in both lists. If you dont want this, you have to copy your Arc objects too.
ArrayList<ArrayList<Arc>> rotalar1 = new ArrayList<ArrayList<Arc>>();
ArrayList<ArrayList<Arc>> rotalar2 = new ArrayList<ArrayList<Arc>>();
for(ArrayList<Arc> list : rotalar1)
{
rotalar2.add(new ArrayList<Arc>(list));
}
This is another way, using Collections.copy(dest,src)
for(ArrayList<Arc> list : rotalar1)
{
ArrayList<Arc> copy = new ArrayList<>();
Collections.copy(copy, list); //or copy.addAll(list);
rotalar2.add(copy);
}
This problem is soved now:
rotalar2.get(random1).remove(random3);
rotalar2.get(random2).remove(random4);
but this will still take effect on both lists:
rotalar2.get(rndList).get(rndArc).set(xvy)
If you want to fix this problem too, you can do something like this:
ArrayList<ArrayList<Arc>> rotalar1 = new ArrayList<ArrayList<Arc>>();
ArrayList<ArrayList<Arc>> rotalar2 = new ArrayList<ArrayList<Arc>>();
for(ArrayList<Arc> list : rotalar1)
{
ArrayList<Arc> tmpList = new ArrayList<>();
for(Arc arcObj : list)
{
tmpList.add(copyOfyourArc); //TODO how do you want to creat a copy of Arc obj?
}
rotalar2.add(tmpList);
}
Method addAll does shallow copy which means it copies all the reference of object (not actual Object) from rotalar1 to rotalar2.
One way, you need to iterate over each object(Arc) and clone
it and add it to new list.
One other way is deep copy using serialization. Example Code
You are not deep copying your list.
The problem is, that your lists contain references to objects. If you copy that (list of) refereces to your second list, both references (the original and the copied one) are pointing to the very same object. Every change applied to the object through the referenc in the second list, will be visible in the first list as well.
To deep copy the collection, you could e.g. iterate over it and manually copy each index.
You should implement your own method to do a deep copy within the Arc class. The method should create a new instance of the object and set all fields(attributes) to the value that the current object has. This method should return a new Object of type Arc that has all the same values as the object trying to be copied. You should then iterate over your arraylist(s) and use your copy method on each object and add the new object to a new arraylist which will be a copy of your original arraylist. Example:
//I don't know the attributes of your Arc class this is just an example
public Arc deepCopy()
{
Arc copyOfArc = new Arc(this.field, this.field2, this.field3, this.field4, etc...);
//if you don't set everything in the constructor then you should use your setters here.
copyOfArc.setField5(this.Field5);
etc...
return copyOfArc;
}
Use this method to iterate over your arraylist and copy each arc object to a new arraylist.
Here is an example of using the deepCopy() method to copy your objects to new arraylist:
ArrayList<ArrayList<Arc>> rotalar2 = new ArrayList<ArrayList<Arc>>();
int counter = 0;
for(ArrayList<Arc> temp : rotalar1)
{
rotalar2.add(new ArrayList<Arc>());
for(Arc temp1 : temp)
{
rotalar2.get(counter).add(temp1.deepCopy());
}
counter++;
}
This will copy arraylist rotalar1 to arraylist rotalar2 with a deepCopy so each arraylist will have its own objects and won't effect each other anymore.

How to copy java.util.list Collection

I am implementing a Java class responsible for ordering java.util.List. The problem comes when I use this class. I'm able to ordering the list but I want to copy the "original" list without modification so that I could register every change made on the original list. The sorted list contains object and one of its fields stores a classification id, and this id it is updated with the index value of the list.
I tried to use clone method and it keeps the list unsorted but the changes made on original list are updated in the clone list too.
Is there any way to accomplish it?
My Code:
List<Torero> listaTorero = tbTlgTorerolHome.findByExample(new Torero());
List<Torero> listaToreroTemp = ((List<Torero>) ((ArrayList<Torero>) listaTorero).clone());
Clasificacion clasificacion = new Clasificacion();
Iterator<Torero> iterTorero = clasificacion.getClasificacion(listaTorero, torero).iterator(); //Sorting List
A Clasificacion method:
public List<Torero> getClasificacion(List<Torero> listaToreroTemp, Torero torero)
{
List<Torero> listaTorero = new ArrayList<Torero>();
Collections.sort(listaToreroTemp,new ToreroClasifiacionComparator());
Iterator<Torero> iterTorero = listaToreroTemp.iterator();
int index=1;
while(iterTorero.hasNext())
{
Torero toreroTemp = iterTorero.next();
toreroTemp.setNumClasificacion(index);
listaTorero.add(toreroTemp);
index=index+1;
}
return listaTorero;
}
You may create a new list with an input of a previous list like so:
List one = new ArrayList()
//... add data, sort, etc
List two = new ArrayList(one);
This will allow you to modify the order or what elemtents are contained independent of the first list.
Keep in mind that the two lists will contain the same objects though, so if you modify an object in List two, the same object will be modified in list one.
example:
MyObject value1 = one.get(0);
MyObject value2 = two.get(0);
value1 == value2 //true
value1.setName("hello");
value2.getName(); //returns "hello"
Edit
To avoid this you need a deep copy of each element in the list like so:
List<Torero> one = new ArrayList<Torero>();
//add elements
List<Torero> two = new Arraylist<Torero>();
for(Torero t : one){
Torero copy = deepCopy(t);
two.add(copy);
}
with copy like the following:
public Torero deepCopy(Torero input){
Torero copy = new Torero();
copy.setValue(input.getValue());//.. copy primitives, deep copy objects again
return copy;
}
Use the ArrayList copy constructor, then sort that.
List oldList;
List newList = new ArrayList(oldList);
Collections.sort(newList);
After making the copy, any changes to newList do not affect oldList.
Note however that only the references are copied, so the two lists share the same objects, so changes made to elements of one list affect the elements of the other.

2d arraylists in java (why are the collections the same eventually)

I have a 2D ArrayList. The ArrayList contains 10 ArrayLists. I tried the following code:
This is the main 2D ArrayList. Inside the main ArrayList there are10 ArrayLists:
ArrayList<ArrayList<Items>> arrayList = new ArrayList<ArrayList<Items>>();
Here I tried to create a copy of one of the ArrayList (selectedRow is just a number which says which ArrayList I get)
ArrayList<Items> newList = new ArrayList<Items>(arrayList.get(selectedRow));
After that I create another ArrayList:
ArrayList<Items> changeList = new ArrayList<Items>(it.returnTheNewArrayList(newList,randomItem));
Then in another class I created this method. The purpose of this method is to change an attribute of one of the objects.
public ArrayList<Items> returnTheNewArrayList(ArrayList<Items> a,int item){
int randomBin = r.nextInt(50);
for(Items i:a){
if(item==i.itemIds()){
while(randomBin==i.bins()){
randomBin = r.nextInt(50);
}
i.setBin(randomBin);
}
}
return a;
}
Finally, I set the new ArrayList in the 2D ArrayList
arrayList.set(whichList, changeList);
This is the procedure. I have find out, that when I run this procedure, both newList and changeList are the same. In both of these ArrayLists I'm saving the change I did in the method returnTheNewArrayList (I found out it with the debugging). But I want to change only one (the changeList).
What did I do wrong?
The lists contain references to objects. When you call i.setBin(...) that's (presumably) making a change to the object itself.
Each list has an independent copy of the references - so you could remove an element from one list without affecting the other - but they're only references.
Imagine you gave two people clipboards, with the same list of home addresses on. One person went and painted the front door of every house list on their clipboard red, then the second person visited all the same houses. The second person would see red doors, wouldn't they? It's the same thing here. The lists contain references, not objects.
If you want the lists to be completely independent, you'll need to populate them with references to different objects.
EDIT: I've just noticed that you'll also need to change your returnTheNewArrayList method, which actually isn't even creating a new ArrayList in the first place!
public ArrayList<Items> returnTheNewArrayList(ArrayList<Items> a,int item) {
// Stuff which doesn't change the value of a...
return a;
}
Again, the value of a is just a reference to the list... so when you return the same reference back, you're not returning a new ArrayList at all.
You really need to understand how references and objects work in Java - it's absolutely crucial to working with the language.
Inside of the returnTheNewArrayList method, you first need to clone a. Otherwise you will be modifying the original ArrayList and the original Items. Jon did a nice job of explaining why, so I won't go into it here. Your code could look something like:
ArrayList<Items> clone = new ArrayList<Items>(a.size());
for(Items item: a) clone.add(item.clone());
//modify clone here
return clone;
Since you've written the Items class yourself, you will need to implement the Cloneable interface yourself.
See the clone method's wikipedia page for more information.
The newList and changeList are not the same (not == ) but their content are identical.
Your "Item" objects are passed by reference that's why the two lists references the same Items.
To get a brand new reference you should create a new instance of Item in method returnTheNewArrayList (10 new instances for 10 new references.)
public ArrayList<Items> returnTheNewArrayList(ArrayList<Items> a,int item){
//create a new List
ArrayList<Items> newList = new ArrayList<Items>();
int randomBin = r.nextInt(50);
for(Items oldItem:a){
// make a copy of Item to get a new instance of Item for the new List
Item newItem = new Item(oldItem);
if(item==newItem.itemIds()){
while(randomBin==newItem.bins()){
randomBin = r.nextInt(50);
}
newItem.setBin(randomBin);
}
newList.add(newItem);
}
return newList;
}

Categories

Resources