Cloning

Well!!!! after a post on PHP this heading might sound a bit out off track.But!!!!! Java is my favourite and probably some days back one of my mentors, mentioned this term and then what???I researched on intricacies of Cloning and any how could not resist myself from writing this post!!!!!!

So,here we go —>

First of all,though I will restrict myself to cloning examples only in java,But Cloning is a part of php5 also, and fundamentals and core concepts always remain the same,be it any language so this post can be considered as a general topic and examples I will mention will be very simple from a begginner’s point of view,So any 1 who doesn’t know Java could even refer it!!!!!!!!!!!

All of you might be familiar with the term CLONING.You might have heard about DOLLY, the clone of a sheep,first clone that was made in 1997.She died when she was 6 yrs old.

So,Dolly was identical to her mother sheep in both appearance as well as characterstics.Similarly a clone in Java or php  is also identical to the object which is cloned i.e. the variables which the parent object holds with there assigned values will now be replicated to the cloned object but cloned object will be at a different memory address.Like

ORIGINAL OBJECT   (int a=5)                        CLONED OBJECT(int a=5)

memory address=7071                                memory address=7072

The problem with clones??

Cloning poses a serious risk of producing children who are stillborn, unhealthy, severely malformed or disabled.Even Dolly died because of  physical defects in  lungs.None of  the clones made till date has been successful!!!

Similarly clones in programming world are also unhealthy.Before coming to the disadvantages of clones lets discuss



What OBJECT CLONING is all about?

1)The way to make an identical copy of object is to invoke clone() on that object.

2)When u invoke clone(),it should either

          a)return an object reference to a copy of the object upon which it is invoked

          b)throw CloneNotSupportedException

Firstly,lemme explain point :

b)  throw      CloneNotSupportedException

Since clone() is declared in class Object,which is the root of the class hierarchy ,it is inherited by every Java object.

So,when you invoke clone() on any object say for example like this:

A  a=new A();

A  b=a.clone();//invoking clone on object “a”


The object “a” is eligible for invoking clone() on it only and only if the class “A” to which it belongs  implements Cloneable interface.

                                     Now what is Cloneable interface??????

Well,it is a Marker Interface?A marker interface is a sort of tag to give java compiler a message so that it can add special behaviour to the class implementing it.Marker Interface has no members in it.

Remember class Object only contains clone() but does not implement Cloneable interface,therefore either the class containing the object to be cloned or one of its superclasses other than Object must implement Cloneable interface.If not,then whenever you will call clone() on the object it will throw CloneNotSupportedException

Now come to point:

a)return an object reference to a copy of the object upon which it is invoked

Simple,if your class or one of its superclasses is implementing Cloneable interface than no error will come and clone() will create  a new instance of the object with all the fields initialized to values identical to the object being cloned,and returns a reference to the new object.


DEEP  VS  SHALLOW  CLONING

Here we go:

1)class MilkCup implements Cloneable {

2)  private int innerMilk;

3)   public Object clone() {
4)        try {
5)           return super.clone();
6)       }
7)       catch (CloneNotSupportedException e) {
8)           // This should never happen
9)            throw new InternalError(e.toString());
10)       }
11)   }

12)   public void add(int amount) {
13)       innerMilk += amount;
14)   }

15)   public int releaseOneSipOfMilk(int sipSizeMilk) {
16)       int sip = sipSizeMilk;
17)       if (innerMilk < sipSizeMilk) {
18)           sip = innerMilk;
19)       }
20)       innerMilk -= sip;
21)        return sip;
22)   }

23)  public int spillEntireMilk() {
24)      int all = innerMilk;
25)       innerMilk = 0;
26)        return all;
27)    }
28)   }

                       Now here comes cloning.Look carefully

29)class Example1 {
30)   public static void main(String[] args) {

31)      MilkCup original = new MilkCup();
32)      original.add(75); // Original now contains 75 ml of milk
33)      MilkCup copyclone = (MilkCup) original.clone();
34)       copyclone.releaseOneSipOfMilk(25); // copyclone now contains 50 ml of coffee

35)       int origAmount = original.spillEntireMilk();
36)       int copyAmount = copyclone.spillEntireMilk();
37)      System.out.println("Original has " + origAmount
38)           + " ml of milk.");
39)      System.out.println("Copy has " + copyAmount
40)           + " ml of milk.");
41)    }
42)}

What is happening inside this piece of code.

Observe line nos 29 to 42

1)We have instantiated a new MilkCup object and given it an initial value of 75ml. of milk.

2)The clone() is then invoked on MilkCup object.

3)Observe lines 3 to 11 we have declared a clone method.Why?By default clone() is protected that means only subclasses and members of the same package will be able to invoke clone() on object.But if you want any class in any package to access clone() then you will have to override it and make it public.

4)When clone() is invoked on MilkCup object referred by original reference,it invokes clone()(line 3-11) in MilkCup’s superclass Object.

5)The clone() then creates a new instance of MilkCup as copyclone and initializes its one field innerMilk to 75.Object’s clone (line 3-11) returns a reference to the new object referred by copyclone which is then returned by MilkCup’s clone().

6)The reference returned is of type object therefore we downcasted it in line no 33 before assigning it to local variable copyclone.

7)Finally 25ml is removed from copyclone so copyclone now contains 50ml of milk.

8)O/P will be Original has 75ml of milk .

  Copy has 50ml of milk.

Do u think cloning is as simple as that?

Actually the answer is simply NO.This is basically called SHALLOW CLONING means everything that is cloned is superficial.What if the private variable innerMilk itself referenced some other object???

In that case also cloning happens in the similar fashion but the problem is the copy object will get a duplicate reference to the object innerMilk will reference to.

Let me simplify it-:::::2 much complications!!!!!!

1)class MilkCup implements Cloneable {

2)   private Milk innerMilk = new Milk(0);

3)   public Object clone() {
4)        try {
5)           return super.clone();
6)       }
7)       catch (CloneNotSupportedException e) {
8)           // This should never happen
9)            throw new InternalError(e.toString());
10)       }
11)   }

12)   public void add(int amount) {
13)       innerMilk.add(amount);
14)   }

15)   public int releaseOneSipOfMilk(int sipSizeMilk) {
16)       return innerMilk.remove(sipSizeMilk);
17)   }

18)  public int spillEntireMilk() {
19)      return innerMilk.removeAll();
20)    }
21)   }

22)public class Milk implements Cloneable {
23)   private int volume; // Volume in milliliters
24)   Milk(int volume) {
25)        this.volume = volume;
26)   }
27)   public Object clone() {
28)       try {
29)           return super.clone();
30)        }
31)       catch (CloneNotSupportedException e) {
32)           // This should never happen
33)          throw new InternalError(e.toString());
34)       }
35)  }

36)   public void add(int amount) {
37)       volume += amount;
38)   }
39)    public int remove(int amount) {
40)       int v = amount;
41)       if (volume < amount) {
42)          v = volume;
43)       }
44)       volume -= v;
45)       return v;
46)    }
47)   public int removeAll() {
48)      int all = volume;
49)       volume = 0;
50)      return all;
51)   }
52)}

53)class Example2 {
54)   public static void main(String[] args) {
55)       MilkCup original = new MilkCup();
56)        original.add(75); // Original now contains 75 ml of coffee
57)       MilkCup copyclone = (MilkCup) original.clone();
58)       copyclone.releaseOneSipOfMilk(25);
59)       // Copy now contains 50 ml of coffee.
60)      // Unfortunately, so does original.
61)      int origAmount = original.spillEntireMilk();
62)      int copyAmount = copy.spillEntireMilk();
63)        System.out.println("Original has " + origAmount
64)          + " ml of coffee.");
65)        System.out.println("Copy has " + copyAmount
66)           + " ml of coffee.");
67)    }
68)}

1) Check line no2.Here innerMilk is an object of Milk class.Now all the calculation part is happening inside Milk class and then being returned to MilkCup and then returned to main method.Gotcha????

2)simple-::::On analysing the code you will get sort of this picture

The picture is not so clear but still by arrows you can make out that though different pointers are created for clone and copy clone but the private innerMilk member in both of them is object of Milk and is referencing to the same variable volume.THis is basically the problem with default cloning.As a result both original and copy will contain 50 ml of milk which is incorrect.

Default cloning supported is SHALLOW CLONING.And in such type of cloning the references that a variable is making are not cloned instead the cloned object itself starts referring the same reference that the original object’s  variables are referring to.!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Quite obvious the solution will be

1)We will change the way our public clone() will behave.

2)The new behaviour of super.clone will be that before returning the reference of new cloned object it will be modified and then it will return the reference of new cloned object….Got it?How?

First the Milk object referred by innerMilk will be cloned

A reference to the cloned Milk object will then be stored in the innerMilk variable of the cloned MilkCup object but those Milk objects are exact duplicates of each other.

This is the new version of clone->

public Object clone() {
        MilkCup copyCup = null;
        try {
            copyCup = (MilkCup) super.clone();
        }
        catch (CloneNotSupportedException e) {
            // this should never happen
            throw new InternalError(e.toString());
        }
        copyCup.innerCoffee = (Milk) innerCoffee.clone();
        return copyCup;
    }

THis can grow more and more complicated!!!!!!!!!!!!!!
THis is referred to as deep cloning and now original and copy clone will
again contain 75ml and 50ml respectively.

As far as I can think cloning is not a good way of duplication.Firstly a lot of memory consumption happens when we clone.

But the need of cloning cannot be ignored even,why?

Having a cloned copy of something means you can have “before” and “after” versions. You can leave the original alone while you test something out with a copy. You can provide undo by simply reverting to the original version.


Some superficial reasons as to why clone should not be used are:

1) the return type of clone() is Object, and needs to be explicitly cast back into the appropriate type.

2) one often cannot access the clone() method on an abstract type. Most interfaces and abstract classes in Java do not specify a public clone() method. As a result, often the only way to use the clone() method is if you know the actual class of an object; which is contrary to the abstraction principle of using the most generic type possible. For example, if one has a List reference in Java, one cannot invoke clone() on that reference because List specifies no public clone() method. Actual implementations of List likeArrayList and LinkedList all generally have clone() methods themselves, but it is inconvenient and bad abstraction to carry around the actual class type of an object.

3) no constructor is called on the object being cloned. As a result, it is your responsibility, as a writer of the clone method, to make sure all the members have been properly set. Here is an example of where things could go wrong. Consider a class keeping track of the total number of objects of that type, using a static int member. In the constructors you would increase the count. However, if you clone the object, since no constructor is called, the count will not truly reflect the number of objects!

4)if the class has final fields, these can’t be given a value in the clone method. This leads to problems with properly initializing the object’s final fields. If the final field is referring to some internal state of the object, then the cloned object ends up sharing the internal state and this surely is not correct for mutable objects.

This topic probably has no end.The concepts can go as deep as possible.I am still going deeper on this topic.This link has made me even more confused:http://www.agiledeveloper.com/articles/cloning072002.htm

I will regularly update this topic after doing all sorts of research.Till then We will revert back to our sweet simple posts on PHP!!!!!!!!!!

Enjoy the post…:)))))))))


					
Advertisements

2 Comments

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s