1

I am learning Java about object clone. I am really confused by shallow clone and deep clone. Below is a sample code from Core Java

public class Employee implements Cloneable { private String name; private Date hireDay; public Employee(String n,double s) { this.name=n; hireDay=new Date(); } public void setHireDay(int year,int month,int day) { Date newhireDay=new GregorianCalendar(year,month-1,day).getTime(); hireDay.setTime(newhireDay.getTime()); } public Employee clone() throws CloneNotSupportedException { Employee cloned=(Employee) super.clone(); //clone mutable fields //cloned.hireDay=(Date) hireDay.clone(); return cloned; } public String toString() { return "Employee[name=]"+ name+" salary= "+salary+" hireday.getTIme() "+hireDay+"]"; } } public class cloneTest { public static void main(String[] args) { try{ Employee original =new Employee("john"); Employee cloned=original.clone(); original.setHireDay(1993,2,22); cloned.setHireDay(2000,11,22); System.out.println("original="+original); System.out.println("cloned= "+cloned); } catch(CloneNotSupportedException e){ e.printStackTrace(); } } } 

In this case, output of original object and cloned object are the same.Since I didn't clone the mutable field,the change made on cloned objects will affects original object. But when I change the method setHireDay into this:

public void setHireDay(int year,int month,int day) { hireDay=new GregorianCalendar(year,month-1,day).getTime(); } 

I did change the value of field hireDay in cloned object but it doesn't affect original object.I don't know why

2
  • "I am really confused by shallow clone and deep clone.". Yes :) A deep copy should be that way, that changes aren´t in the source too. That´s why it is a "deep" copy: Not only a second instance of your class is created, but every member in it is newly created too for the copy. Commented Mar 30, 2014 at 3:48
  • If you are learning about cloning, here's the #1 thing you should know about cloning: It is inherently broken. So, DON'T DO IT, unless you ABSOLUTELY have to. You may ask, what is an alternative to cloning then? Use immutable objects. You should spend some time reading on how to create immutable classes in Java. Commented Jul 8, 2015 at 2:26

1 Answer 1

2

In the changed setHireDay method the "hireDay" variable is pointing to another memory location while in the first setHireDay method the memory location is unchanged (but the value it refers to is changed). It helps to think of Object variables like "hireDay" as primitive long values that specify a memory address (a.k.a. pointers). At this memory address the actual Object data is stored (like the time-value of the "hireDay" variable). In the case of hireDay = new Date() the memory address is changed, while in the case of hireDay.setTime(x) the memory address stays the same but the value referred to is changed.

Below a demonstration of this (run it as a Java application and compare the output with the source code) plus an example of how to make a deep copy versus a shallow copy.

import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Date; import java.util.GregorianCalendar; public class CloneTest implements Cloneable, Serializable { private static final long serialVersionUID = 5971741470680723802L; public static void main(String[] args) { try { CloneTest original = new CloneTest(); System.out.println(); System.out.println("### shallow clone"); CloneTest cloned=original.clone(); compare(original, cloned); original.setHireDay(1993,2,22); cloned.setHireDay(2000,11,22); compare(original, cloned); System.out.println(); System.out.println("### shallow clone - mutable hiredate"); cloned.hireDayMutable = true; cloned.setHireDay(2002,11,22); compare(original, cloned); System.out.println(); System.out.println("### deep clone"); cloned = clone(original); compare(original, cloned); cloned.setHireDay(2004,11,22); compare(original, cloned); } catch(Exception e){ e.printStackTrace(); } } private Date hireDay; public boolean hireDayMutable; public CloneTest() { super(); hireDay=new Date(); System.out.println("New instance"); } public void setHireDay(int year, int month, int day) { if (hireDayMutable) { hireDay = new GregorianCalendar(year,month-1,day).getTime(); } else { Date newhireDay = new GregorianCalendar(year,month-1,day).getTime(); hireDay.setTime(newhireDay.getTime()); } } public CloneTest clone() throws CloneNotSupportedException { CloneTest cloned = (CloneTest)super.clone(); return cloned; } public String toString() { return "CloneTest[hireday=" + hireDay + "]"; } public static void compare(CloneTest original, CloneTest cloned) { System.out.println(); System.out.println("The same object : " + (cloned == original)); System.out.println("The same hireDate: " + (cloned.hireDay == original.hireDay)); System.out.println("original = " + original); System.out.println("cloned = " + cloned); } /** * Clones an object by serializing and then unserializing it ("deep copy"). */ @SuppressWarnings("hiding") public static <T> T clone(T o) { return clone(o, 512); } @SuppressWarnings({ "unchecked", "hiding" }) public static <T> T clone(T o, int bufSize) { return (T) unserialize(serialize(o, bufSize)); } public static byte[] serialize(Object o, int bufSize) { ByteArrayOutputStream baos = new ByteArrayOutputStream(bufSize); try { ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject((Serializable)o); oos.close(); } catch (IOException e) { throw new RuntimeException(e); } byte[] ba = baos.toByteArray(); // log.trace("Serialized size: {}", ba.length); return ba; } public static Object unserialize(byte[] ba) { Object o = null; try { ByteArrayInputStream bais = new ByteArrayInputStream(ba); ObjectInputStream oin = new ObjectInputStream(bais); o = oin.readObject(); } catch (Exception e) { throw new RuntimeException(e); } return o; } } 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.