Need some inputs:
Lets say i have N ArrayList and in each i am adding foo() object.
Foo foo = new Foo()
A.add(foo);
B.add(foo);
N.add(foo);
Now modification done on any one foo() object will reflect in all the other arraylist?
If YES WHY? and
whether this behaviour can also be achieved using any other collection like Vector etc...?
IF i make foo as null will it reflect in all arraylist?
Yes, because all lists only contain a reference to the same objects
Yes, all collections work like that
No, because you can only set a reference to null, and each list has a copy of the reference.
Any implementation of Collection API such as ArrayList or Vector hold reference to an object in heap memory so when you would get an index of a List by get(index) method, you achive reference to object so:
Yes, if get an index of list by get(index) method and then change the stat of the achieved object, changes stay in memory.
Yes,All Collection API have this behavior.
No,When achieve to a index of list, act is: "You achieve a copy of reference to object" and when set it to null, list instance don't any change.
Related
I have a problem with understanding one thing.
I have:
List<Map> resultList = new ArrayList<Map>();
Then this resultList is filled with some data
resultList.addAll(somemethod(something, something, else));
Later in the method I have this kind of code:
Map timeSpan = someMethod(resultList, date);
timeSpan.put(KEY_ART, VALUE_ART);
timeSpan.put(KEY_TIMESPAN, true);
So I have a question now. If Map timeSpan is a map referenced to an element of List<Map> resultList, is using the put() method on the timeSpan map affecting the element in resultList?
I am asking this question cause a collegue told me that this is working this way - modifying an element in timeSpan is also modyfying this element in resultList. She is far more experienced, and I don't just want to believe her but I want to understand why it is working this way.
You have to remember that resultList is a reference to an object. You can copy this reference around and use it in many way, in many places but there is only one object. This means when you alter the object, there is only one view of this object.
Java objects are always instantiated as a reference to a memory space. If you create a second object from the first object, both will point to the same memory space:
Map a = new HashMap();
Map B=b = a;
Here, we first create an instance A which points to a HashMap which is created somewhere in memory. Next, we create an instance of Map b and have it reference to the same memory space as Map a. Now, when we change map b, these changes will also be made to Map a, since they point to the same memory construct.
In you case, you have a List this in itself is a memory construct. Each item in the list references a seperate Map. These are each also created somewhere in memory. The moment you retreive a Map from the list, you retreive the reference to the memory space where the actual map is located. After that, it works exactly as the example.
addAll() will copy all the elements to the current list from the Collection/List you passed as an argument to this method. In your case, as each element is a reference to Map object, after copying, you have 2 references pointing to same Map object, so changes done using any one reference are visible through the other one.
The short answer is yes, put() for timeSpan is affecting resultList, because when a method returns a Map, which is got from the List, it returns a reference to the heap where map elements are located.
I have following code in my program:
...
private void generateStack() {
List<AdvertisementsModel> adsForModel = Storage.getAdsForId(model.getId());
...
adsForModel.clear();
...
Storage is static class with static fields and methods. generateStack method is in another class and in instance object. Why does adsForModel.clear(); affects the list in Storage class if asdForModel reference is not final?
Storage.getAdsForId(...) returns a copy of the reference to the same List object. So calls via this reference effect the same list. When you call Storage.getAdsForId there is no new List created - just a new reference to the same list.
Therefore it's good practise to either return explicitly ImmutableList or making a defensive copy of the list in Storage.getAdsForId(...) and returning the copy.
Be aware that you need to make a deep copy when AdvertisementsModel is mutable or you'll run into the same problem on a different level. (Otherwise you may have a list copy now but both lists still containing references to the same AdvertisementsModel objects and changing them still effect the list contents inside Storage.)
Java is pass by value (of the reference). So, if Storage.getAdsForId(model.getId()) returns a reference which is staticly stored within Storage then calling clear() on it in the instance will affect the same List within Storage as well. You could do this instead:
return new ArrayList<AdvertisementsModel>(Storage.getAdsForId(model.getId()));
to return a copy of the list instead which would avoid affecting the list within Storage. Of course, modifying an element of this list will still affect the same element present within the list in Storage. To avoid that, you'd have to deep copy each element in the list.
getAdsForId should return a copy of the list, otherwise it will return a reference and calling clear on the list will empty the original one.
If it is final, is the original list not affected? I have doubts about that... It's the same list instance. For this, I'd use either
new ArrayList<AdvertisementsModel>(Storage.getAdsForId(model.getId()));
which creates a new list instance and if possible, modified the Storage class to return an UnmofifiableList of the original list:
return Collections.unmodifiableList(adsForIdList);
I'd prefer this, as this solution does not create a new List instance with each call, it is the responsibility of the receiving code to decide if that needs to be created or not. However, in multithreaded environments, if the original list might be modified, this might result in ConcurrentModificationExceptions - so in that case it is wiser to create a "defensive copy" of the list in the getter itself. Be sure to keep in mind, that then the modifications to the copy will not affect the original list...
I have encountered a problem in one of my Java projects, which causes bugs.
The problem sounds as following:
I have two arrays. Let's name them firstArray and secondArray. Object in this case is a seperate class created by me. It works, the array can be filled with objects of that type.
Object[] firstArray= new Object[];
Object[] secondArray = new Object[];
Now, when I get an element out of the first array, edit it and then copy it in the second array, the object from the first array gets altered too.
tempObj = firstArray[3];
tempObj.modifySomething();
secondArray[3] = tempObj;
Whenever I do this, the (in this case) 3rd element(actually 4th) of the first array gets the modifications. I don't want this. I want the first Array to remain intact, unmodified, and the objects I have extracted from the first array and then modified should be stored in the second so that the second array is actually the first array after some code has been run.
P.S. Even if I get the element from the first array with Array.get(Array, index) and then modify it, the element still gets modified in the first array.
Hopefully you understood what I wanted to say, and if so, please lend me a hand :)
Thank you!
You're going to have to create a new object.
The problem is the modifySomething call. When you do that, it alters the object on which it's called. So if you've only got one object (even by two names), you can't call modifySomething or they will both change.
When you say secondArray[3] = firstArray[3], you aren't creating a new object: you're just assigning a reference. Going through an intermediate temporary reference doesn't change that.
You'll need code that looks like this:
Object tempObj = firstArray[3].clone();
tempObj.modifySomething();
secondArray[3] = tempObj;
The clone() method must return a new object divorced from the original but having identical properties.
When you retrieve an element from your array, you have a reference to it. So if you modify it, the modification are shered through all the object's references.
In order to leave it intact, you should use some method like Object.clone() or create a new Object and use its constructor to initialize its fields.
The object extracted from the first array needs to be cloned to create a new instance that is seperate. Otherwise the modification will affect the object in the first array as it is the same object.
When you retrieve an element from your array, you get a reference to it. So if you modify it, the modification are shared through all the object's references.
In order to leave it intact, you should use some method like Object.clone() or create a new method which take in input your retrieved object and return a new one alike.
In Java, when you do this secondArray[3] = tempObj;, you actually put the reference to the array, not the real object
So firstArray[3] and secondArray[3] point to the same real object
What you need to do is to create a new object that is identical to your original object, and put the reference of the new object to your secondArray
It might worth to point out that default clone() function only does a shallow copy, so if you have mutable objects in your object's fields, it might cause some problems. Take a look at this article about how to do a deep copy
Just a thought question here. In C++, I could do the following:
vector<vector<string> > data;
// add data into data
//..
data[0].push_back( "somedata" );
And I would expect somedata to get written to the vector array because the [] notation gives me access to the object by reference. What about in Java? If I:
List<List<String>> data = new ArrayList<List<String>>();
// add data into data
//..
data.get(0).add( "somedata" );
Would this actually write somedata into the data object? Or would it create a new copy of the element at data(0), add somedata to that, and then that object disappears into GC sometime down the line?
ArrayList is a List backed-up by array (in order to enable random access) the list stores references to real elements so when you add a new element as you mentioned, the reference to it will be added to the ArrayList (and the backing Array will point to this List element).
You must first understand that List, String, etc. in Java, these types are reference types. Their values are references, which are pointers to objects. Thus, List<List<String>> in Java would be most equivalent to vector<vector<string *> *> * in C++. You cannot have a direct "object value" in Java like you can in C++; objects are always hidden behind a pointer.
So to answer your question, yes, the Java code you show works, but for very different reasons. In your Java code, you have a list of references (pointers). You want to modify stuff in the object that is pointed to by one of these pointers, but you do not need to change the pointer itself. Thus, there is no need to return the element by reference. It is sufficient to return the element (a pointer) by value.
Your question "Would this actually write somedata into the data object?" is kind of ambiguous. The code modifies the object pointed to by the first element of the list. Whether this constitutes modifying the list object itself depends on what you consider to be "part of" an object. As explained earlier, the list object contains a collection of pointers to objects. Should the objects pointed to by these pointers to be considered "part of" the list object? There could be many pointers to the same object. So if you consider it to be a part of the container, then what happens when there are pointers to the same object in multiple containers, is the object then part of all of these containers at the same time?
The answer to "Or would it create a new copy of the element at data(0)" is, it creates a copy of the pointer that is the first element. It does not create a copy of the object that the pointer points to.
Almost. The pattern you need is:
List<List<String>> data = new ArrayList<List<String>>();
data.add(new List<String>());
data.get(0).add( "somedata" );
The first line creates only the "outer" List of Lists; you have to populate it with one or more Lists (of Strings) before you can add data to the inner lists.
so suppose i have
ArrayList<E> X = new ArrayList<E>();
and I pass X into some parameter:
Something Y = new Something(X);
it will pass X by reference rather than by value and I don't want this....class Something has a field with Arraylist type that is supposed to be distinct to itself and I don't want to go and iterate through the damn arraylist and set it individually just to instantiate the field...
is there a way to easily make Java pass any object parameters by value rather than reference without having have to implement cloneable interface on all my objects which is a pain in the butt
As Java do not allow direct pointer manipulation, you cannot dereference a pointer. You have to live with references. If you want to prevent the passed object from being modified, you have to clone it or make it immutable (like String). Also keep in mind that object references are passed-by-value. So statements like "Java has pass-by-reference" is not exact, if we take pass-by-reference in the C++ sense.
It actually passes X by value. (The Something constructor can't change the variable X in the calling code.) X happens to be a reference to an ArrayList, not an ArrayList. You could try:
Something Y = new Something(new ArrayList<E>(X));
Instead of creating a new object everytime you can pass an unmodifiable list. This list is read-only and the user has to create another list if he wants to make any modification.
List unmodifiableList = Collections.unmodifiableList(list);
List newList = new ArrayList(unmodifiableList);
Collections.sort(newList);
The constructor of ArrayList takes an existing list, reads its elements (without modifying them!), and adds them to the new List.