class
Avoid side-effects with Object.clone
In this example we shall show you how to avoid side-effects when using Object.clone. To avoid side-effects when using Object.clone we have performed the following steps:
- We have created a class,
Enemy, that has a method,void mungeFunc(SideEffects sdf), where it gets an object ofSideEffectsclass and changes its fields’ values. SideEffectsclass implements the Cloneable interface to indicate to thejava.lang.Object.clone()method that it is legal to make a field-for-field copy of instances of that class.- The class has a public Date field, that will be cloned and a
volatileint field, that cannot be cloned. It also has a constructor using its fields. SideEffectsalso has a method,void process(), that creates a newEnemyinstance, callsmungFunc()method ofEnemyclass, using theclone()method ofSideEffectsand then callsmungFunc()again, using theSideEffectsobject where the method is run.- We create a new instance of
SideEffectsand call itsprocess()method. - The
dateandyearfields ofSideEffectshave the values they get when a new instance of SideEffects is created. - When
mungFunc()is called using the clone object ofSideEffects, although thedatefield is cloned, since theyearfield is volatile it is not cloned, so it cannot be changed. - When
mungFunc()is called using the original object of SideEffects, both fields are changed by themungFunc()method,
as described in the code snippet below.
package com.javacodegeeks.snippets.core;
import java.util.Date;
/**
* Simple demo of avoiding side-effects by using Object.clone() to duplicate an
* object before passing it to your enemy's methods. Cloneable is a "marker"
* interface: it has no methods, but is tested for by Object.clone.
*
* If you implement it, you tell Object.clone that your data is stable enough
* that field-by-field copy is OK.
*/
class Enemy {
public void mungeFunc(SideEffects sdf) {
System.out.println("Object is " + sdf);
sdf.year = 0;
sdf.date.setYear(71); // Ignore deprecation warnings
}
}
public class SideEffects implements Cloneable {
/**
* When we clone a "SideEffects", this REFERENCE gets cloned
*/
public Date date;
/**
* When we clone a "SideEffects", this integer does NOT get cloned
*/
volatile int year;
public static void main(String[] argv) throws CloneNotSupportedException {
new SideEffects().process();
}
SideEffects() {
date = new Date(); // today
year = date.getYear();
}
public void process() throws CloneNotSupportedException {
Enemy enemy = new Enemy();
System.out.println("We have seen the enemy, and he is " + enemy);
System.out.println("Today is " + date );
System.out.println("And the year is " + year);
enemy.mungeFunc((SideEffects) this.clone());
System.out.println("Why, I believe it is now " + date);
if (year == 0) // should not happen!!
{
System.out.println("** PANIC IN YEAR ZERO **");
}
System.out.println("But wait, the year is still " + year);
enemy.mungeFunc(this);
System.out.println("Now I'm certain that it's " + date);
System.out.println("Now the year is " + year);
}
}
Output:
We have seen the enemy, and he is methodoverloading.Enemy@33e92e10
Today is Fri Jun 22 16:53:40 EEST 2012
And the year is 112
Object is methodoverloading.SideEffects@7a5d5033
Why, I believe it is now Tue Jun 22 16:53:40 EEST 1971
But wait, the year is still 112
Object is methodoverloading.SideEffects@43c8308
Now I'm certain that it's Tue Jun 22 16:53:40 EEST 1971
Now the year is 0
This was an example of how to avoid side-effects when using Object.clone in Java.
