Solved

Deep Clone Example

Posted on 2014-02-11
11
570 Views
Last Modified: 2014-02-22
Hi,

I am working on below example

http://javapapers.com/core-java/java-clone-shallow-copy-and-deep-copy/

i have not understood what author is mentioning as below relating to deep clone.
Deep Copy
When you need a deep copy then you need to implement it yourself. When the copied object contains some other object its references are copied recursively in deep copy. When you implement deep copy be careful as you might fall for cyclic dependencies. If you don’t want to implement deep copy yourselves then you can go for serialization. It does implements deep copy implicitly and gracefully handling cyclic dependencies.






One more disadvantage with this clone system is that, most of the interface / abstract class writers in java forget to put a public clone method. For example you can take List. So when you want to clone their implementations you have to ignore the abstract type and use actual implementations like ArrayList by name. This completely removes the advantage and goodness of abstractness.

When implementing a singleton pattern, if its superclass implements a public clone() method, to prevent your subclass from using this class’s clone() method to obtain a copy overwrite it and throw an exception of type  CloneNotSupportedException.

Note that clone is not for instantiation and initialization. It should not be synonymously used as creating a new object. Because the constructor of the cloned objects may never get invoked in the process. It is about copying the object in discussion and not creating new. It completely depends on the clone implementation. One more disadvantage (what to do there are so many), clone prevents the use of final fields. We have to find roundabout ways to copy the final fields into the copied object.


My code looks as below

class Employeee implements Cloneable {
	private String name;

	private String designation;

	public Employeee() {
		this.setDesignation("Programmer");
	}

	public String getDesignation() {
		return designation;
	}

	public void setDesignation(String designation) {
		this.designation = designation;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Object clone() throws CloneNotSupportedException {
		/*
		 * CloneExample2222 copyObj = new CloneExample2222();
		 * copyObj.setDesignation(this.designation); copyObj.setName(this.name);
		 * return copyObj;
		 */
		return super.clone();
	}
}

public class CloneExample2222 {
	public static void main(String arg[]) {
		Employeee jwz = new Employeee();
		jwz.setName("Jamie Zawinski");
		try {
			Employeee joel = (Employeee) jwz.clone();
			System.out.println(joel.getName());
			System.out.println(joel.getDesignation());
		} catch (CloneNotSupportedException cnse) {
			System.out.println("Cloneable should be implemented. " + cnse);
		}
	}
}

Open in new window



I got output as below which is also not clear to me

Jamie Zawinski
Programmer

How is implementign cloneable different from sefializable?
please advise
Any links resources ideas highly appreciated. Thanks in advance
0
Comment
Question by:gudii9
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 5
11 Comments
 
LVL 27

Expert Comment

by:dpearson
ID: 39851929
The main point to grasp is the difference between a shallow copy and a deep copy.

This only matters when the object being copied, contains other objects.
E.g.

public MyList {
    private List<String> m_Names ;

    public MyList(List<String> names) { m_Names = names ; }

    public void remove(String name) { m_Names.remove(name) ; }
    public String toString() { return "List=" + m_Names ; }

    public MyList createShallowCopy() {
       MyList newList = new MyList(m_Names) ;
    }

    public MyList createDeepCopy() {
       MyList newList = new ArrayList<String>() ;
       newList.addAll(this.m_Names) ;
       return newList ;
    }
}

Open in new window


Take a look at the differences between createShallowCopy() and createDeepCopy().

Imagine we have:
List<String> names = new ArrayList<String>() ;
names.add("Sam") ;
names.add("Tony") ;
names.add("Lisa") ;
MyList start = new MyList(names) ;

Now if we create a shallow copy:
MyList shallowCopy = start.createShallowCopy() ;
MyList deepCopy = start.createDeepCopy() ;

the list *inside* shallowCopy and start are both the same list.

So if we now do:
start.toString() returns "Sam, Tony, Lisa"
shallowCopy.toString() returns "Sam, Tony, Lisa"
deepCopy.toString() returns "Sam, Tony, Lisa"

start.remove("Sam") ;
start.toString() returns "Tony, Lisa".

But:
shallowCopy.toString() also returns "Tony, Lisa" because the list inside shallowCopy is the same list as the one inside start.

That may be OK, or it may not.  But it's different from deep copy:

deepCopy.toString() returns "Sam, Tony, Lisa" because it contains a different internal list than start does.  So when we removed "Sam" it didn't affect deep copy.

Does that all make sense?

The rest of the article just talks about specifically what clone does (a  shallow copy) and some of the reasons why it's usually best avoided.

Also if you implement serializable you can potentially use that to make a copy since you serialize the data into some form and then deserialize that to get back to the original.  If you do that without throwing away the original then it produces a copy.  So it's one way to copy an object.

Doug
0
 
LVL 7

Author Comment

by:gudii9
ID: 39854622
deepCopy.toString() returns "Sam, Tony, Lisa" because it contains a different internal list than start does.  So when we removed "Sam" it didn't affect deep copy.


How and where do i see to find it contains different internal list. What is the name of internal list deepCopy, shallowCopy has. For me it seems both has same list as below

   public MyList createShallowCopy() {
       MyList newList = new MyList(m_Names) ;
    }

    public MyList createDeepCopy() {
       MyList newList = new ArrayList<String>() ;
       newList.addAll(this.m_Names) ;
       return newList ;
    }
Please advise
0
 
LVL 27

Expert Comment

by:dpearson
ID: 39854695
Oops - my code has some typos which may have thrown you off.

Should be:

 public MyList createShallowCopy() {
       MyList newList = new MyList(m_Names) ;
       return newList ;
    }

    public MyList createDeepCopy() {
       List<String> newInternalList = new ArrayList<String>() ;
       newInternalList.addAll(this.m_Names) ;
       MyList newList = new MyList(newInternalList) ;
       return newList ;
    }

Open in new window


Can you see now how the deep copy is creating a newInternalList while the shallow copy doesn't do that?

Doug
0
Monthly Recap

May was a big month for new releases from Linux Academy! Take a look at what our team built recently in our blog. You can access the newest releases from our blog.

 
LVL 7

Author Comment

by:gudii9
ID: 39857357
deepCopy.toString() returns "Sam, Tony, Lisa" because it contains a different internal list than start does.  So when we removed "Sam" it didn't affect deep copy.




 List<String> newInternalList = new ArrayList<String>() ;
       newInternalList.addAll(this.m_Names)


I wonder why  newInternalList  again contains m_Names similar to Shallow Copy.

I did not get the gist of removing list member etc and how it is different in both cases?

I am still not very clear. Can you please post complete code which i can run and see. Please advise
0
 
LVL 7

Author Comment

by:gudii9
ID: 39870615
Can you see now how the deep copy is creating a newInternalList while the shallow copy doesn't do that?


I do not understand clearly.

I modified program as below

 public class MyList {
    private List<String> m_Names ;

    public MyList(List<String> names) { m_Names = names ; }

    public void remove(String name) { m_Names.remove(name) ; }
    public String toString() { return "List=" + m_Names ; }

   public MyList createShallowCopy() {
       MyList newList = new MyList(m_Names) ;
       return newList ;
    }

    public MyList createDeepCopy() {
       List<String> newInternalList = new ArrayList<String>() ;
       newInternalList.addAll(this.m_Names) ;
       MyList newList = new MyList(newInternalList) ;
       return newList ;
    }

}

Open in new window


I see compilation errors like
List cannot be resolved to a type at line 2 and following lines where m_names is used. can you please post complete code. please advise
0
 
LVL 27

Expert Comment

by:dpearson
ID: 39870895
Add this to the top of the file - so it can resolve List:

import java.util.*;

Doug
0
 
LVL 7

Author Comment

by:gudii9
ID: 39871285
import java.util.ArrayList;
import java.util.List;

public class MyList {
    private List<String> m_Names ;

    public MyList(List<String> names) { m_Names = names ; }

    public void remove(String name) { m_Names.remove(name) ; }
    public String toString() { return "List=" + m_Names ; }

   public MyList createShallowCopy() {
       MyList newList = new MyList(m_Names) ;
       return newList ;
    }

    public MyList createDeepCopy() {
       List<String> newInternalList = new ArrayList<String>() ;
       newInternalList.addAll(this.m_Names) ;
       MyList newList = new MyList(newInternalList) ;
       return newList ;
    }

}

Open in new window



It fixed the compilation error once i imported list and array list.

But there is no main method or anything like that. How to run. Can you please provide me complete code to understand this example
0
 
LVL 27

Accepted Solution

by:
dpearson earned 500 total points
ID: 39871489
OK here's a full example, which I hope explains this concept:

import java.util.*;

public class MyList {

	private List<String> m_Names ;

	public MyList(List<String> names) { m_Names = names ; }

	public void remove(String name) { m_Names.remove(name) ; }
	public String toString() { return "List=" + m_Names ; }

	public MyList createShallowCopy() {
		MyList newList = new MyList(m_Names) ;
		return newList ;
	}

	public MyList createDeepCopy() {
		List<String> newInternalList = new ArrayList<String>() ;
		newInternalList.addAll(this.m_Names) ;
		MyList newList = new MyList(newInternalList) ;
		return newList ;
	}

	public static void main(String[] args) {
		List<String> names = new ArrayList() ;
		names.addAll(Arrays.asList(new String[]  { "Alan", "Bill", "Clare" } )) ;

        MyList list1 = new MyList(names) ;
		MyList list2 = list1.createShallowCopy() ;
		MyList list3 = list1.createDeepCopy() ;

		System.out.println("List1 (before change) = " + list1) ;
		System.out.println("List2 (shallow copied) = " + list2) ;
		System.out.println("List3 (deep copied) = " + list3) ;

                // Now we modify the names list - to see which of these
               // "copies" are completely separate copies and which are still
               // sharing data with the original list1.
		names.add("Doug") ;

		System.out.println("List1 (after change) = " + list1) ;
		System.out.println("List2 (shallow copied) = " + list2) ;
		System.out.println("List3 (deep copied) = " + list3) ;
    }
}

Open in new window


The output you should get is:

// See how list1, list2 and list3 are all copies of each other:
List1 (before change) = List=[Alan, Bill, Clare]
List2 (shallow copied) = List=[Alan, Bill, Clare]
List3 (deep copied) = List=[Alan, Bill, Clare]

// But then we modify the internal list "names" to add a new name to it.
// The shallow copy of MyList is sharing the list of names, so it sees the change.
// While the deep copy of MyList creates a new internal list, so it does not see the change.
List1 (after change) = List=[Alan, Bill, Clare, Doug]
List2 (shallow copied) = List=[Alan, Bill, Clare, Doug]
List3 (deep copied) = List=[Alan, Bill, Clare]

The shallow copy and the deep copy behavior are different.  Either may be correct in a given situation - it depends on what you mean by "making a copy of the original".

Does that finally make sense?

Doug
0
 
LVL 7

Author Comment

by:gudii9
ID: 39871603
It makes much more sense. I am still trying to digest.

So the link

http://javapapers.com/core-java/java-clone-shallow-copy-and-deep-copy/


author program is only clone example right which internally uses shallow copy not deep copy.

>>Employee joel = (Employee) jwz.clone();

author in this example using shallow copy(clone) cloned  jamie(jwz) into joe1 object right.
so joe1 name , designation also became same as jamie. So output is

Jamie Zawinski

Programmer


Is my understanding is correct?
0
 
LVL 27

Expert Comment

by:dpearson
ID: 39871757
Yes that's right.  Clone() is a built-in method but it only does a shallow copy.  If you want a deep copy you need to write it yourself.

(There are lots of problems with clone().  The usual advice is to avoid it because unless you're very careful with it, it will do something different from what you want - like this example of a shallow copy).

Doug
0
 
LVL 7

Author Comment

by:gudii9
ID: 39880155
0

Featured Post

Transaction Monitoring Vs. Real User Monitoring

Synthetic Transaction Monitoring Vs. Real User Monitoring: When To Use Each Approach? In this article, we will discuss two major monitoring approaches: Synthetic Transaction and Real User Monitoring.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This was posted to the Netbeans forum a Feb, 2010 and I also sent it to Verisign. Who didn't help much in my struggles to get my application signed. ------------------------- Start The idea here is to target your cell phones with the correct…
Introduction This article is the first of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article explains our test automation goals. Then rationale is given for the tools we use to a…
Video by: Michael
Viewers learn about how to reduce the potential repetitiveness of coding in main by developing methods to perform specific tasks for their program. Additionally, objects are introduced for the purpose of learning how to call methods in Java. Define …
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.

729 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question