Let's say I have an Object called Index, this object has two attributes Long id; , String name; and I have two ArrayLists in my page, the problem is that when I edit the name of the index object in the first list it is being edited in the second list as well, here is my code to make the problem more understandable:
Index index1 = new Index();
index1.setName("1");
index1.setId(1);
List<Index> indexes = new ArrayList<Index>();
indexes.add(index1);
List<Index> newIndexes = new ArrayList<Index>();
newIndexes.add(index1);
Now if I update the name of the index in the indexes list it is being updated in the newIndexes list. note: the object index has equals method on the Id field.
Thanks
The reference index1 is the same for both lists, so changing the Index referenced will change it in both.
Cloning the List per se won't fix your issue, as it'll clone the List but not its elements.
You need to perform a deep-clone of the List and its elements (or initialize a new ArrayList, as you do, and clone each of the previous List's elements) to solve your issue.
See here for the how-to.
That is because index1 is just a reference to the object. So, your are basically adding the same reference to both of the lists. You need to copy the object before adding to the second list.
When you add the object to both the lists, the reference of that object is copied to the lists. And that's why when you object the object from one list, it is reflected back in the other. To avoid this, you need to create a copy of the object and add it to the other list, so that both do not refer to the same object.
This is happening because when you use "Add" on array list (and in almost every data collection object) the collection is adding the "reference" of the object to its list, and not creating a new object.
Thus, when both index1 objects at indexes and newIndexes are basically the same one. When changing it no matter where, it will be changed at the other as well.
Related
I am currently thinking about how to create n objects of type x in Java.
Thought experiment: You want to create all entries from a specific database table as an object.
The number of entries are given by counting them.
The object to be created is a model of a table entry.
My current strategy would be to create Lists foreach column.
After that, I would create an Object by looping through the Lists, append it to a HashSet and continue with the next row.
But probably there is a problem with the references, because the created objects would have the same name and if I remember right, I would overwrite the pointer by creating another object in this case. So it's the question if the HashSet still contains the old reference or not.
Besides this solution would be very ineffective cause of the number of loops.
Pseudocode
HashSet for objects
lists of every column
iterate through lists
create object with values at position i of loop
append object to HashSet
If you have a clue about to solve the pointer problem or if it does not exist, I would be glad about your answer. Moreover, I would be grateful for more suited solutions.
PS: I did not found any design pattern for this use case
If I'm correctly understanding the "pointer problem" to which you refer, it does not exist. I think you may have some misconceptions about how references, as they are properly called in Java, work.
Take the following code
Set<MyObject> mySet = new HashSet<>();
MyObject myOb;
myOb = new MyObject("Object #1"); // 1
mySet.add(myOb); // 2
myOb = new MyObject("Object #2"); // 3
mySet.add(myOb); // 4
At the lines marked // 1 and // 2 we create a MyObject object with the data "Object #" and add it into a Set; the variable myOb references the object we've just created.
If we were to print the contents of the set at this point, we'd see
{["Object #1"]}
At line // 3, we create another new MyObject object, this time with the data "Object #2", and assign myOb to reference it.
But wait! We've just added myOb (which was referencing an object with the data "Object #1") to the set, and now we're changing myOb to reference a different object. Does that mean our set suddenly looks like:
{["Object 2"]}
No, it doesn't, because what was added to the set was not myOb itself, but the rather the myObject object that myOb happened to be referencing at the moment that mySet.add(myOb) was called. All the set received was a reference to a MyObject instance; it hasn't the slightest clue that the reference happened to be stored in the variable myOb.
Thus we can make myOb reference (or "point to", if you prefer) any other MyObject object (or even the same object again) without affecting the set in the slightest.
I have a simple question.
Lets say we have a Map, for example a Map<String, Object>
I want a method that returns a list of all values inside the Map.
The approach i use is the following:
I create a List<Object> myList = new ArrayList<>();
Get an iterator from the value set of the Map.
For each element inside the iterator i put a reference in the myList list.
Return the list
...later for each element i use i wrap it inside a synchronized block because the list contains references.
Now i am woring about using an easier apporach. The one i mean is the following:
return new ArrayList(myMap.values());
As you see in this case i simply use the constructor of the List interface which accepts a Collection.
And finally my question is:
If i use the second approach do i still get references or it copies the value objects that are inside the map?
In both cases you will get "shallow" copy of collecion, so both arrays will keep references to the same objects.
return new ArrayList(myMap.values()) will return an ArrayList containing the references of the original values of the Map. No copies of the values instances are created.
Note that if your Map contains duplicate values (i.e. values that are equal to each other), your ArrayList will also contain duplicate values. If you want to eliminate the duplicates, you should create a Set of the values instead of a List.
In either case you'll get a copy of the reference (so called "shallow copy").
There is no deep-copying (creating a completely new object with meaningfully equivalent fields -- also deep-copied) involved.
I need to pass the same ArrayList from the main function to 3 different functions (all in different classes).
When the 1st function receives the ArrayList, it makes changes not only in the local copy of the list but also the original ArrayList in the main method gets modified. This indicates that the changes are being made at the memory address.
So, in the first function I copied the received arraylist into another arraylist of the same type, using:
for(int i=0;i<valuex.size();i++)
{
temp1=valuex.get(i);
VALUE.add(temp1);
}
This worked for the first time when I introduced this modification but then the same problem restored. Later I made three copies of the arraylist and passed each copy to each of the 3 functions. This too failed.
I didn't use
clone();
because this created the same problem some time back..
Please help...
You have described a shallow copy - you've made a fresh list, but you've got the same objects in each list.
If this isn't working for you, it suggests your method is modifying the list objects. To avoid this being a problem, you'll have to perform a deep copy - creating copies of each of your objects.
For example:
List<Foo> oldList = // ...
List<Foo> newList = new ArrayList<>();
for (Foo foo : oldList) {
Foo newFoo = new Foo(foo); // copy constructor
newList.add(newFoo);
}
When you passed a copy of the list to your three methods, you passed a reference to a copy of the list as a data structure. However, both lists, in memory, ended up pointing to the very same objects.
If your methods are changing the actual objects that the lists are pointing to, and you'd like to avoid that, then cloning the list is not enough: you must clone each and every object in the list as well.
By the way: the reason that clone() didn't work for you is that clone() only performs a shallow clone of the list: it creates a brand new ArrayList instance in memory, however the list's constituents are still the same objects (in memory) as the objects pointed-to by the original list.
You can just create a new ArrayList based on your existing arrayList before passing it in as argument.
List existingList = new ArrayList();
o1.m1(new ArrayList(existingList));
o2.m2(new ArrayList(existingList));
o3.m3(new ArrayList(existingList));
ArrayList contructor allows you to create a new ArrayList based on an existing collection.
http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#ArrayList(java.util.Collection)
today i dealt with a Java problem that really confused me.
I have the following code:
List<ObjectXY> someList = obj.getListOfObjectsXY(); // getter returns 2 elements
someList.add(new ObjectXY());
obj.getListOfObjectsXY(); // getter now returns 3 elements
When i add an element to a list, the getter gets some kind of overwritten. Is this because someList acts like a reference on the result of the getter in this case? Or what else causes this effect?
I solved the problem with the following code by using another list:
List<ObjectXY> someList = obj.getListOfObjectsXY(); // result: 2 elements
List<ObjectXY> someOtherList = new ArrayList<ObjectXY>();
someOtherList.addAll(someList);
someOtherList.add(new ObjectXY());
obj.getListOfObjectsXY(); // result: 2 elements
But i am still some kind of confused because i didn't expect Java to behave this way.
Can anyone explain to me what i did wrong and why it is so?
Thanks in advance!
The returned result is indeed just a copy of a reference to the same object as you are using internally. Counting on the caller to not modify the object is error-prone.
One solution is to return a reference to an unmodifiable list wrapping your list. See Collections.unmodifiableList(). The getter caller will be unable to modify your list.
Is this because someList acts like a reference on the result of the
getter in this case?
Yes. The list you received was just a reference to the same, original list you had. Any changes made on this variable would be reflected on the original list.
By adding the list's values to a new list you explicitly constructed a new object and thus they are separated.
In your case, obj.getListOfObjectsXY() everytime return you the same object and in Java object references are pass-by-value. So, when you do a someList.add(new ObjectXY());, it's actually setting the property of the object someList which is poiting to obj.getListOfObjectsXY().
And in the latter case, you are just copying someList to someOtherList. Then you added one more element to the same someOtherList but not to the someList. So, you getting 2 elements in
obj.getListOfObjectsXY(); is perfectly valid.
For example I have a reference to an mItem object of my List<mItem> mList collection. Is that possible to get a reference to mList using mItem?
The short answer is no. The items in a list don't know they are in a list. (Unless of course you add a reference to the list inside your mItem object.)
Short answer: no.
Adding an item to a list adds a reference to that object to the list. It does not affect the object itself.
You can check to see if an item is in a specific list, with mList.contains(mItem) which returns true if the item is in mList. Alternatively if you really need to, you could as others have suggested implement a version of List that informs each item that the list has a reference to that item. The overhead would be rather messy though.
Meta question: why do you need this functionality?
As jzd said... you can add a field to your mItem class (for example referenceHolder)
mItem(Object ref){
referenceHolder = ref;
}
class with List:
mList.add(new mItem(this));
something like that should work :) but its kind of weird ;), because normally "The items in a list don't know they are in a list. "
EDIT: and as said before - "One object should be a member of multiple collections" - so you would need to change type of my referenceHolder to some list or array, to make that able to happen.
EDIT2: that's just reference to object holding that list (if one object will have multiple lists, you wont be able to know witch of them is holding that sepecified mItem object), to reference to List itself you will need (as said in comment ;)) custom list implementation adding references to stored objects with this in add() method.
If you have a container for all you lists, you can call contains on each one to find which list the item is in.
Note: for a list you can have the same element multiple time, and across multiple list.
BTW: If you don't want duplicates in a list and don't care about the order of elements then a Set may be your best choice.