I am trying to clone an object of MyGraph and I want it to be a deep copy so the arraylists inside the object are also cloned. Right now I have:
public static MyGraph deepCopy(MyGraph G){
MyGraph Copy = (MyGraph) G.clone();
Copy.VertexG = (ArrayList<Integer>) G.VertexG.clone();
Copy.EdgeG = (ArrayList<String>) G.EdgeG.clone();
return Copy;
}
This returns an error when it tries to clone the arraylist. I am not sure if this is the right way to add the arraylists to the object.
The clone operation in ArrayList returns a shallow copy of the object, and will not be suitable for your purposes. The manual workaround is to:
Create a target array list of the same size as the source list
Iterate the source list and create a clone of each of it's items, into the target list
Obviously, this will only work if the array list contains items that implement clone, and in addition that the items clone operation actually returns a deep copy. In other words, its not guaranteed. Actually, implementing deep clone functionality for Java objects is not at all easy, refer to extensive discussions in Java: recommended solution for deep cloning/copying an instance and other SO threads to get a feel for the options available. In addition to the answers provided there, here are some other options:
Serialization
If all (the required) objects in your hierarchy can be serialized then you can use this simple code to do a deep clone:
public MyGraph deepCopy() {
try {
final ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
final ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
oos.close();
final ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(baos.toByteArray()));
final MyGraph clone = (QuicksortTest) ois.readObject();
return clone;
} catch (final Exception e) {
throw new RuntimeException("Cloning failed");
}
}
Note that some deep-clone libraries combine standard Java serialization with reflection hacks and/or byte code instrumentation in order to make the entire object hierarchy fully serializable. You may, or may not, need that.
Copy tools
For example, Dozer, provide fast deep-copy functionality. Orika can also achieve the same, albeit with more configuration:
public MyGraph deepCopy() {
final DozerBeanMapper mapper = new DozerBeanMapper();
final QuicksortTest clone = mapper.map(this, MyGraph.class);
return clone;
}
The only downside of course, being the additional dependencies you need to pull into your project.
On a total tangent, your deepCopy method should not be static. Also, you should seriously considering encapsulating the state of your object by making it private and implementing getters/setters.
Every class you call clone() on has to implement the Cloneable interface. From your comments, i understand your MyGraph class does not implement the Cloneable interface. In that case, Object.clone() throws the CloneNotSupportedException.
Trying to do deep copy with cloning is complicated as you need to ensure that all classes implement Cloneable interface and they have clone() definition.
Better way would be to do it through Copy Constructor or Serialization. Here is my blog on which i have discussed it in detail. hope it helps :)
A fundamental conceptual problem with cloning in Java [arguably the fundamental problem] is it's possible for a field of a type like List<String> to represent at least five very different things:
The only extant reference to a mutable list, which is used to encapsulate the mutable state thereof, but which--being the only extant reference--would not encapsulate its identity (the list could be replaced with a different list holding the same items, without altering the program's semantics). A correct clone of the object that contains this field would hold a reference to a different list holding the same items.
A reference to a mutable list which, while it would allow itself to be mutated, will never be exposed to anything that would actually mutate it. This reference may be shared with other code only if that other code will refrain from mutating the list or exposing it to code that might do so. A correct clone of the object that contains this field could hold a reference to either the original list or a different list holding the same items.
A reference to an immutable list. This reference may be shared freely with other code without regard for how that code might expose it. As above, the correct clone of the object containing this field could hold a reference to either the original list or a copy.
A reference to a mutable list which is owned by some other object, which is held for purpose of binding this to those aspects of the other object's state which are encapsulated in the list. A correct clone of the object holding the field must hold a reference to that same list, and not a copy thereof.
A reference to a mutable list which this object owns, but to which other objects also have a reference for purpose of either observing this object's state, or feeding information to this object. The object holding this field cannot be correctly cloned in isolation, though it might be possible to clone a group of inter-connected objects and give the new set of objects a set of interconnections which was isomorphic to those in the original group.
The concrete type of the object to which the field holds a reference may distinguish between some of the above cases, but it cannot distinguish among all of them. In particular, the first and fourth scenarios require different behavior on the part of the cloning method, despite the fact that in both scenarios the reference might likely pointing to an ArrayList<string>.
Related
I need help with something. my code is of the following template.
Assume customObject has multiple property1, property2, ..property100.
List<CustomObject> customObjectList = /*<method call to external API that returns the said list >*/
if(customObjectList != null && customObjectList.size() > 0){
//*** point A ***<clone the Object>
resultList = <some method that process the above list>(customObjectList)
if(resultList.size() > 0){
for(Iterator<Map.Entry<CustomObject, ExternalResponse>> itr = resultList.entrySet().iterator(); itr.hasNext();) {
//code that modifies the properties in the CustomObjects
//*** point B ***resetAProperty(<Object clone>)
}
}
}
At point B, I need the one unmodified specific property of original object to use in the method. I have two strategies for this:
Clone the object at point A, and use the cloned copy to get the
property as shown in above code. At point A, Use a for loop and a
Map to form an associate array of object names, property original
values and traverse them to get the property initial value at point
B
Avoid Cloning because it always requires Deep Cloning
.clone() especially on a List will almost always end in tears because you would have to deep clone all the objects in the list, all their referenced objects, and so on.
Deep Cloning means you have to make a binary copy of every last object in the Object graph. Just copying a reference will give you a shallow copy and you will see any changes that are made to the referenced object. Just miss one property and you will have a hell of a time finding that bug.
Solution
What you should do is make all your CustomObject instances Immutable and then you don't need to worry about versioning, they can never change, mutation would involve creating a new instance that is also Immutable and a complete different object. Then you never had to worry about versions.
Of course all the instance variables that point to other objects will need to be Immutable as well. This is the same problem as the deep clone but taking from another angle. A much more manageable angle.
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...
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.
I have two lists (list1 and list2) containing references to some objects, where some of the list entries may point to the same object. Then, for various reasons, I am serializing these lists to two separate files. Finally, when I deserialize the lists, I would like to ensure that I am not re-creating more objects than needed. In other words, it should still be possible for some entry of List1 to point to the same object as some entry in List2.
MyObject obj = new MyObject();
List<MyObject> list1 = new ArrayList<MyObject>();
List<MyObject> list2 = new ArrayList<MyObject>();
list1.add(obj);
list2.add(obj);
// serialize to file1.ser
ObjectOutputStream oos = new ObjectOutputStream(...);
oos.writeObject(list1);
oos.close();
// serialize to file2.ser
oos = new ObjectOutputStream(...);
oos.writeObject(list2);
oos.close();
I think that sections 3.4 and A.2 of the spec say that deserialization strictly results in the creation of new objects, but I'm not sure. If so, some possible solutions might involve:
Implementing equals() and hashCode() and checking references manually.
Creating a "container class" to hold everything and then serializing the container class.
Is there an easy way to ensure that objects are not duplicated upon deserialization?
Thanks.
After deserialization of the second list you could iterate over it's the elements and replace duplicates by a reference to the first list.
According to 3.7 The readResolve Method the readResolve() method is not invoked on the object until the object is fully constructed.
I think that sections 3.4 and A.2 of the spec say that deserialization strictly results in the creation of new objects, but I'm not sure. If so, some possible solutions might involve: ...
2, Creating a "container class" to hold everything and then serializing the container class.
I read these statements as "if I my understanding about deserialization always creating new objects is incorrect, then solution #2 of writing both lists wrapped in a container class to a single stream is an acceptable solution."
If I am understanding you correctly, this means you think writing out through a single container containing both lists won't work because it will still result in duplicate objects ("strictly results in ... new objects"). This is incorrect. When writing out the graph of objects (your wrapper class), each object is only serialized once, no matter how many occurrences in the graph. When the graph is read back in, that object is not duplicated.
http://java.sun.com/javase/6/docs/api/java/io/ObjectOutputStream.html
The default serialization mechanism for an object writes the class of the object, the class signature, and the values of all non-transient and non-static fields. References to other objects (except in transient or static fields) cause those objects to be written also. Multiple references to a single object are encoded using a reference sharing mechanism so that graphs of objects can be restored to the same shape as when the original was written.
So, if you can, use option #2.
Creating a "container class" to hold everything and then serializing the container class.
You can override the readResolve() method to replace what's read from the stream with anything you want.
private Object readResolve() throws ObjectStreamException {
...
}
This is typically used for enforcing singletons. Prior to Java 5 it was also used for typesafe enums. I've never seen it used for this but scenario but I guess there's no reason it couldn't be.
Now this will work with individual objects that you control but I can't see how you'd make it with a List. It could ensure that the objects returned in that list aren't duplicated (by whatever criteria you deem).
I understand that in order to copy an arraylist and have two lists independent of one another you must use a deep copy (copying the objects from one list to another not just the references), however is there a way this can be done cross-class?
For example; I am calling Class2 from Class1. In Class2 objects are added to an ArrayList of custom objects upon an event. I would like to be able to transfer this ArrayList to Class1 but whenever I try I get a NullPointer.
Any clues??
This is highly indicative of a design flaw.
See if you can't accomplish the same goal by wrapping your list in a class, sharing the class and using it to control access to the list.
The only case where this wouldn't just outright work is if your two classes must modify the list independently.
If this is a requirement, then I would probably hand a different instance of the wrapper class to each modifying class (with a reference to the same source list), then have a way for newly added data to be tagged with an ID referring to the original class--that way when you query, the wrapper would only return untagged items (items that were part of the original shared list) and items tagged with it's own ID.
Either that or the wrapper class could contain a second list and when queried, return the combined results of the original and second lists.
I've almost never wanted a deep copy. It happens, but it's quite rare.
If you post more info, maybe we can be more specific in helping with the redesign.
ALSO: (Edit)
Chances are that the copied array list isn't your problem--it's probably that it wasn't TRULY a deep copy. For a deep copy, it means you implement a copy method (I believe they are supposed to be called .clone(), I never use this stuff--as I said, it's bad juju) for each object in the array list, then you call your copy method on each one to get the new copy in your next list.
Furthermore, any objects referenced by your copied object should probably be cloned as well. "Deep" means all the way down the tree.
I'm guessing you're failing somewhere in the process.
I'd really like to hear why you feel you need a copy instead of a reference.
My suggestion is for you to create a getArray() method and call it from the other class. This method should create a copy of the ArrayList because you should not "transfer" variables within classes; always with get() method so OO paradigm stays intact.
Do something like this:
Class 1
public ArrayList<Object> getArray() {
ArrayList<Object> aux = new ArrayList<Object>();
for(Object x : list) //object is the string, int, etc...
aux.add(x.clone()) //assuming the Object has a clone method!
return aux;
}
On Class 2, just call this method. Then just look at the test from the other answer about the null exception, should work.
Hope it helps.