I have a class called Program which hold a grid. It has two methods possi() which saves all possible ways you can enter the grid and saves ArrayList possi with all possible entry points and method solve which actually goes and enters the grid with the provided entry point. I've done mazesolvers using dfs and bfs but there my problem is that solve actually changes the grid substantially usually bfs and dfs dont account for the maze being changed. That is why I am not using them. I want to got through all the possibilities of entry points and further points. My first level of entry points is stored in lev1.possi and I can loop through them. Then I have to create a new instance of a grid since solve will change the structure and apply the solve then return new possi from that new object. So essentially I am creating a new object for each change. The problem is grid.clone() isnt making a new object instead still refering to my old grid.
Program lev1 = new Program();//initializes grid randomly
lev1.possi();//calculates entry points and stores in possi
ArrayList<Program> lev = new ArrayList<Program>();//stores all possible objects
for (int i = 0; i < lev1.possi.size(); i++)//loops through all entry points
{
Program pick = new Program(lev1.grid.clone());//makes a new object
lev.add(pick);
lev.get(i).solve(lev1.possi.get(i));//changes the new object
lev.get(i).possi();//calculates further points to go through
}
I assume grid is some complex type, which contains complex types like an array, etc. In this case clone() does not create a deep copy (i.e. it does not recursively clone the parts like an array).
Here is an example of a clone() method for complex types: In this example we have a type FlightLogEntry which contains a TreeMap. To clone a FlightLogEntry we need to create a new TreeMap and fill the map using the original elements. In this example those elements are not cloned (clone.setAttendant(p, this.attendats.get(p)). If you need an even deeper copy from the clone method (which depends on the usage of the clone) you might want to clone the attendat also like this: clone.setAttendant(p, this.attendats.get(p).clone().
#Override
public FlightLogEntry clone() {
FlightLogEntry clone = (FlightLogEntry) super.clone();
clone.attendants = new TreeMap<Person, Duty>();
for( Person p : this.attendants.keySet() ) {
clone.setAttendant(p, this.attendants.get(p));
}
return clone;
}
You need to instantiate a new grid object in your Program(grid) constructor, then assign the values from the old grid with the new one.
Related
I am trying to make a copy of an ObjectA, which has another ObjectB in it, which also has 6 other ObjectC's, but I dont want to have a copy of ANY of their memory addresses, so if I updated any of the original objects later on, it will not update the copy's values (which consists of all three objects). I have tried implementing the clone() but that still doesnt work for what I am trying to do.
Here is what I am trying to do (yes I know this looks ridiculous...):
void rotateEntireCubeClockwise(){
System.out.println("Changing view of cube...rotating entire cube clockwise...");
CubeAlgorithms a2 = clone();
cube.left = a2.clone().cube.clone().front.clone();
cube.front = a2.clone().cube.clone().right.clone();
a2.clone().rotateTopClockwise(1);
cube.top = a2.clone().cube.clone().top.clone();
a2.clone().rotateTopCounterClockwise(1);//undo
a2.clone().rotateLeftClockwise(2);
cube.back = a2.clone().cube.clone().left.clone();
a2.clone().rotateLeftCounterClockwise(2);//undo
a2.clone().rotateBackClockwise(2);
cube.right = a2.clone().clone().cube.clone().back.clone();
a2.clone().rotateBackCounterClockwise(2);//undo
a2.clone().rotateBottomClockwise(1);
cube.bottom = a2.clone().cube.clone().bottom.clone();
}
public CubeAlgorithms clone() {
try {
return (CubeAlgorithms) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
CubeAlgorithms contains a Cube object, and the Cube object contains 6 CubeSide objects(front, left, back, right, bottom, and top)
Both Cube and CubeSides also contain a clone method similar to the one you see above.
My problem with this code is that I want it to rotate a cube clockwise, however the only rotation that it does is the very last one.
This is generally called a "deep copy." There's not a single way to do it; all of the classes being deeply copied have to help out in one form or another.
One approach is to have a copy constructor (that is, a constructor CubeAlgorithms(CubeAlgorithms)) that does a deep copy on all of the incoming object's fields. Of course, to do a deep copy of those, you need to do something similar to them -- and so on.
Another approach, if your classes are all serializable and performance isn't a huge concern, is to serialize and deserialize your objects. In this, I don't necessarily mean java's built-in serialization: you could use Jackson to JSON-ify them and then read that JSON string back out, etc.
I think your code looks complex because in that method you are trying to clone the object and modify it (rotate it) at the same time.
Also, you are invoking the "clone" method of all the objects several times, so each time you would be creating a new copy. That could explain why only the last operation is applied.
I'd suggest you separate the operations and first clone the entire cube (with all the sub-objects it has inside) and then once you have the new Cube object, then rotate that one (the original one will not be rotated since the second object is a separate one).
To clone the object, you should write a "clone" method in all the classes. The "clone" method should create a new instance of the class, and then populate the attributes by cloning them as well.
For example, in the "Cube" class:
public Cube clone() {
Cube newCube = new Cube();
newCube.front = this.front.clone();
newCube.back = this.back.clone();
newCube.left = this.left.clone();
newCube.right = this.right.clone();
newCube.top = this.top.clone();
newCube.bottom = this.bottom.clone();
return newCube ;
}
You should then implement the other classes' "clone" method in a similar fashion (create a new instance, then populate the attributes with clones of the attributes in the "this" instance).
Once you have successfully cloned the object, then do whatever operation you need to rotate it (and you don't need to call "clone" several times, just clone the cube once).
Cube rotateEntireCubeClockwise(Cube originalCube) {
Cube newCube = originalCube.clone;
// now manipulate the "newCube" to make sure it rotates
// ...
return newCube;
}
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.
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 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
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.