I am trying to make a copy of an object to make some tests on it without affecting the original object. I made this copy() function but the original object is still affected.
Inside the class "I" I have this copy function:
#Override
public Piece copy() {
I newPiece = new I(blocks[0], blocks[1], blocks[2], blocks[3]);
newPiece.STATUS = this.STATUS;
newPiece.FORM = this.FORM;
return newPiece;
}
and I try to make a copy like this:
Piece rotated = piece.copy();
rotated.changeForm();
Class "I" is a subclass of the abstract class Piece with the abstract method copy(). when I do the changeForm() in the copied object it affects the original one too.
SOLVED
the Block objects were passed as reference too so I needed to add a copy() method even for the type Block. Code changed this way:
#Override
public Piece copy() {
I newPiece=new I(blocks[0].copy(),blocks[1].copy(),blocks[2].copy(),blocks[3].copy());
newPiece.STATUS=this.STATUS;
newPiece.FORM=this.FORM;
return newPiece;
}
Every type of Piece attributes or fields that is not a primitive type should be copied too.
So the values of STATUS, blocks[1], blocks[2], blocks[3] and FORM.
I hope it helps.
If the contents of blocks are reference types, you will also have to copy them.
Alternatively you could just make a new constructor for Piece and use it.
Piece newPiece = new Piece(oldPiece.thing1(), oldPiece.thing2().....);
This is the problem, in your copy constructor:
Piece rotated=piece.copy();
That's just copying the reference to the Piece. Both objects will still refer to the same object.
You can use:
Piece rotated = new Piece(piece.copy());
You're not changing the new object, you're changing its contents. Unfortunately, the original object has the same contents, so it appears as though you had done something to the original object.
You have made what is called a shallow copy. It would appear that you need to make a deep copy, which involves making copies of the contents of the original object. In your case, you need to make a copy of blocks[0], blocks[1], etc.
The question that may haunt you is how deep that copy must be. You will no doubt find out, but you may have to go deeper than it would appear at first.
As previous authors mention you should make a deep copy of object, but with your code you're only making a shallow copy.
The fastest and easiest way to deep copy an object in java is to serialize() it and deserialize().
Assuming all your classes implement java.io.Serializable interface:
public static <T extends Serializable> T copy(T orig) {
T obj = null;
try {
// Write the object out to a byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(orig);
out.flush();
out.close();
// Make an input stream from the byte array and read
// a copy of the object back in.
ObjectInputStream in = new ObjectInputStream(
new ByteArrayInputStream(bos.toByteArray()));
obj = (T) in.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
return obj;
}
Related
I am using Concurrenthashmap which stores Objects. I want to get that object and modify it without modifying the hashmap. How do I do it?
Following is my code:
ConcurrentHashMap<String,Employee> dataStorage = new
ConcurrentHashMap<String,Employee>(10000);
dataStorage.put("Employee1", Employee1);
I had added an object of type Employee to the HashMap.
Now when I do a get
Employee employee1 = dataStorage.get("Employee1");
If I modify employee1, the updated object gets stored in the HashMap
How do I modify employee1 without affecting the value stored in HashMap?
You can make a deep copy of the object employee i.e. actually create a new object rather than just passing the memory location of the employee object.
To learn more about deep copy read here.
You can do it by using something like this:
/**
* This method makes a "deep clone" of any object it is given.
*/
public static Object deepClone(Object object) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
For more you can read here.
Also you can use the clone() by implementing Cloneable.
Read here for clone() or here.
Make a deep copy of the Employee object. One possibility here would be to add a copy constructor to your Employee class which copies over the fields:
class Employee {
private String name;
private int ID;
// other fields...
public Employee(Employee other) {
this.name = other.name;
this.ID = other.ID;
// ...
}
}
As you correctly observed, if you do some modification to the Employee object which you get directly from the hashmap, it will "stick" there. Over the course of my life using Java, this behavior has usually been what I wanted but hopefully this answer is one workaround for you to consider.
Employee Employee2 = Employee1.clone();
dataStorage.put("Employee1", Employee2);
I hope this will work.
ConcurrentHashMap<String,Employee> dataStorage = new
ConcurrentHashMap<String,Employee>(10000);
dataStorage.put("Employee1", Employee1.clone());
In most of the cases, the shallow copy should work.
I was reading this answer and he mentioned a link, where author explains why shouldn't we use Cloneable. But, still have doubt what was stated there
If I have an array of Cloneable, you would think that I could run down
that array and clone every element to make a deep copy of the array,
but I can't. You can not cast something to Cloneable and call the clone
method, because Cloneable doesn't have a public clone method and
neither does Object. If you try to cast to Cloneable and call the
clone method, the compiler will say you are trying to call the
protected clone method on object.
But, here I did
Init s = Init.getInstance(); // getting instance
int count=0;
Cloneable[] v = new Cloneable[5]; // creating array
Init x = s;
Init y = new Init(s);
try {
while (count < 5) {
v[count++] = (Cloneable) s.clone(); // casting it.
}
s.setClassName("Example");
System.out.println(((Init) v[2]).getClassName()); // Displaying.
} catch (CloneNotSupportedException ex) {
ex.printStackTrace();
}
I was able to create Cloneable array and I did what author said will cause error Or Did I misunderstood author statement ? Anyone, please help me to understand the reason to choose Copy Constructor over Cloneable.
You are not casting s to Cloneable and then calling clone() on it.
Instead you are calling s.clone() and then casting the result to Clonable.
You are able to do this because s is of type Init and Init has public clone() method.
Do this instead and you will find the compiler shouting,
v[count++] = ((Cloneable) s).clone();
Now let's say you want to clone an array (You obviously only know it's a Cloneable array. Which means you don't know it's actual Type.
Cloneable[] cloneArray = new Cloneable[5];
cloneArray[i] = new Init(); // Let's say it's initialized with different type objects but all `Cloneable`.
for (Cloneable object : cloneArray) {
object.clone(); // Compiler wont allow it. And you don't know what type it is.
}
So, you basically cannot deep clone a Cloneable array.
I'm working on an assignment that deals with array manipulations for Java. Right now I have to delete elements inside the middle of an array. Now I know that arrays, once they're created cannot be changed in length. So I decided to make a new object, and have the former reference point to my new array.
public class A{
public static void main(String[] args){
B test = new B(val);
test.cut(2,4);
test.display();
}
class B{
private Obj[] array;
B(Obj val){
construct something
}
public void cut(int i, int j){
B newObject = new B(val);
...
newObject.array = this.array;
newObject = this;
}
}
The issue is that when I display the test object, it will only show me the original test object contents rather than newObject contents. Since this is a void method, I can't return an object. How do I reference the new object then? The last two lines for my cut method seem to have no effect at all. I know that ArrayList would be preferable for things like this, but this being a homework assignment we are forced to use arrays.
Now I know that arrays, once they're created cannot be changed in length.
This is true.
But the reference pointing to an array inside the B object instance can be changed (as you didn't declare it final):
public void cut(int i, int j){
Object[] newArray = new Object[len];
//... copying array content ...
this.array = newArray;
}
Beware of the thread safety issues such mutability causes. Mutable objects are usually frowned upon...
If the rules of assignment allow the use of class Arrays, this is what you can use instead of your own cut method:
newArray = Arrays.copyOfRange(oldArray, from, to);
In the method cut you create a new object of B then assign the the this reference to it. This has not effect as you have found because the this reference (the actual object) is not changed at all, The newObject is visible only inside this method, once it is terminated, the object is gone.
While you are in the same class B you dont have to create a new Object of it just for the purpose of altering the data it holds. You could just create a new array and copy the original content to it.
For copying the content you could use the method System#arraycopy. If you are not permited to use any jdk helping functionalities, then you could just loop over the original array and copy elements into the new one as you want.
I have a problem with getting a new value of an object. I have a code like that:
...
TimeSchedule[] offspringScheduleOne = new TimeSchedule[AVAILABLE_CLASSROOMS];
...
offspringScheduleOne[i] = genes.get(geneOneIndex).getSchedule()[i];
...
After that assignment offspringScheduleOne[i] and genes.get(geneOneIndex).getSchedule()[i] points the same memory address. I want that: offspringScheduleOne[i] should get the value of the genes.get(geneOneIndex).getSchedule()[i], they musn't be same, they just should have same values.
TimeSchedule class:
public class TimeSchedule extends AlgorithmParameters {
public int[][] timetable = new int[DAYS][HOURS];//DAYS and HOURS are static final variables that comes from AlgorithmParameters
public int[][] getTimetable() {
return timetable;
}
public void setTimetable(int[][] timetable) {
this.timetable = timetable;
}
}
How can I do that?
It actually is copying the value - but you need to understand what that value is.
The value of offspringScheduleOne[0] isn't a TimeSchedule object. It's a reference to a TimeSchedule object. No expression in Java has a value which is an object. It's really important that you understand this.
Now, if you want a copy of the object, you'll have to make that happen yourself. For example, you could include a clone() method in TimeSchedule, and write:
offspringScheduleOne[i] = genes.get(geneOneIndex).getSchedule()[i].clone();
In other words, create a clone of the existing object, and then set offspringScheduleOne[i] to be a reference to that newly created object. Of course, if any of the fields within TimeSchedule is a reference type field, you'll need to consider whether or not you need to clone that object as well...
... or you could add a constructor and call that, or another method, etc. But you need to be absolutely clear that the assignment operator is copying the value, but that value is a reference.
EDIT: Okay, now that you've posted TimeSchedule, a few suggestions:
Stop using public fields. What's the point of having properties if the field is public?
Rather than having properties returning the whole array, change them to access an individual hour, e.g.
public int getTimetable(int day, int hour) {
// TBD: Argument validation
return timetable[day][hour];
}
// Similar for `setTimetable`
Create a clone method like this:
public TimeSchedule clone() {
TimeSchedule copy = new TimeSchedule();
for (int i = 0; i < timetable.length; i++) {
copy.timetable[i] = timetable[i].clone();
}
return copy;
}
(That's slightly wasteful in that it will create the subarrays and then discard them, but let's get something which works first...)
}
public Test clone() {
int[][] timetableCopy = new int[timetable.length][];
for (int i = 0; i < timetable.length; i++) {
timetableCopy[i] = timetable[i].clone();
}
return null;
}
You should create a new TimeSchedule object. Assuming you have a copy constructor you can use this:
TimeSchedule original = genes.get(geneOneIndex).getSchedule()[i];
TimeSchedule copy = new TimeSchedule(original);
offspringScheduleOne[i] = copy;
The constructor should copy the values from original. If you don't have such a constructor you can call get and set methods to copy the values across manually.
TimeSchedule original = genes.get(geneOneIndex).getSchedule()[i];
TimeSchedule copy = new TimeSchedule();
copy.setFoo(original.getFoo());
copy.setBar(original.getBar());
// etc...
offspringScheduleOne[i] = copy;
There's also a clone method that was designed for creating copies of objects, but it's awkward to use and it's probably best to avoid it.
You could let TimeSchedule override the clone method and write
offspringScheduleOne[i] = genes.get(geneOneIndex).getSchedule()[i].clone();
Does anyone have any suggested or established best practices and naming conventions for copy constructors / factory methods etc in Java? In particular, say I have a class Thing and I want a method somewhere that returns a new Thing with the same value as a Thing passed in (or as the instance if it's an instance method). Would you have this as constructor or a static factory method or instance method? What would you call it?
As per the title, I want to avoid clone() and Cloneable.
Effective Java recommends either of the following:
A copy constructor (as noted by others):
public Item(Item item)
A copy factory method:
public static Item newInstance(Item item)
(Also, no copying for immutables)
The primary difference is that with #1 you choose the actual class of the result, and with #2 the implementer can return a subclass. The semantics of the class may guide you into which one is best.
I would call it a copy method or a copy constructor (as the case may be). If it was a static method, then I would call it a factory.
In terms of what to do, the most flexible and long living option is a copy constructor. This gives subclasses the ability to copy themselves just like the parent.
I'd do a constructor
...
public Thing(Thing copyFrom)
{
attr1 = copyFrom.attr1;
attr2 = copyFrom.attr2;
//etc...
}
then when you want to clone it
Thing copy = new Thing(copy from me);
You can overwrite the clone()-method, if you want. Another used practice is a constructor, that takes an object of this type, i.e. new ArrayList(anotherList).
You've got a few options, implement Cloneable, add a copy constructor but my preferred way is to use a method (static or instance) that has a name which is descriptive of what the copy operation is doing - is it a deep or shallow copy, etc.
Use immutable data structures. The only reason you feel that you need clone() is that you're mutating your objects in place. Stop doing that. Think about how you can:
Make your classes final.
Make fields in your classes final and private.
For example, here's a "setter" for an immutable 3D vector object:
public Vector3D setX(double x) {
return new Vector3D(x, this.y, this.z);
}
So I guess what I'm saying is... I use copy constructors instead of mutation, and I just name them according to the attribute that I want to modify.
Another option is to implement the copying method in the source object, e.g.:
interface Has3DCoords {
void setLocation(double x, double y, double z);
void copyCoordsTo(Has3DCoords dest);
}
You would then implement copying with a piece of code like:
class Thing implements Has3DCoords {
private Point3D loc;
// ...
void setLocation(double x, double y, double z) {
loc.setLocation(x, y, z);
// or: loc = new Point3D(x, y, z);
}
void copyCoordsTo(Has3DCoords dest) {
loc.copyCoordsTo(dest);
// or: dest.setLocation(loc.getX(), loc.getY(), loc.getZ());
}
OtherThing createOtherThing() {
OtherThing result = new OtherThing();
this.copyCoordsTo(result);
return result;
}
}
This can be useful if:
It does not make sense to clone the whole object
There is a group of related properties that are often copied as one unit
You do not want to expose loc as a property of Thing
The number of properties is large (or there are many such groups) so a constructor that required all of them as parameters would be unwieldy.
This is not the nicest approach to copying objects but the following is sometimes useful if you wish to perform a deep copy of a Serializable object. This avoids having to write copy constuctors, implement Cloneable or writing factory classes.
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
//Serializes the input object
oos.writeObject(input);
ByteArrayInputStream bais = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
//Copy of the input object
Object output = ois.readObject();
Don't forget to handle the exceptions and to close the streams nicely.