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 ofSideEffects
class and changes its fields’ values. SideEffects
class 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
volatile
int field, that cannot be cloned. It also has a constructor using its fields. SideEffects
also has a method,void process()
, that creates a newEnemy
instance, callsmungFunc()
method ofEnemy
class, using theclone()
method ofSideEffects
and then callsmungFunc()
again, using theSideEffects
object where the method is run.- We create a new instance of
SideEffects
and call itsprocess()
method. - The
date
andyear
fields ofSideEffects
have the values they get when a new instance of SideEffects is created. - When
mungFunc()
is called using the clone object ofSideEffects
, although thedate
field is cloned, since theyear
field 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.