Cloning using super.clone()

Here is a samle code:

class Employee implements Cloneable

{

public Employee clone() throws CloneNotSupportedException

{

return (Employee) super.clone(); // Line 1

}

}

Here Employee class is extending Object class, so when we call super.clone in Line 1 then it should return an Object of class Object.

How come this line does not throws a ClassCastException when we try to execute this line using employee.clone() ?

Why is downcasting allowed although super.clone() here will return an object of type Object?

[576 byte] By [Nandan.Srivastavaa] at [2007-11-26 22:31:43]
# 1
Why shouldn't it work?Actually what clone() is doing is making a copy of your class not of the super class. Your Employee class is an Object as well, so its perfect legal to do it.MeTitus
Me_Titusa at 2007-7-10 11:37:28 > top of Java-index,Java Essentials,Java Programming...
# 2

What clone() in Employee class is doing is that it is calling clone method of Object class. Thats all. An object of Employee class is never created because no code is written for it.

And then it is trying to "downcast" an object which is basically an object of Object class.

I need some more explanation :(

Nandan.Srivastavaa at 2007-7-10 11:37:28 > top of Java-index,Java Essentials,Java Programming...
# 3

A method declared and implemented in the Object class operates on the very object it is invoked against. If it is an Employee object, then on that.

Otherwise getClass().getName() would not be useable beacuase it would only return java.lang.Object.

The clone() method in Object returns a shallow-copy of the given object, provided if the actual type (and not Object itself) implements Cloneable.

BIJ001a at 2007-7-10 11:37:28 > top of Java-index,Java Essentials,Java Programming...
# 4

I understand everything in the above post except how it works in this context.

you people must be right since the downcasting is working, which according to me should give a runtime exception.

Now, I add two methods:

public void callSuperToString(){

System.out.println(super.toString());

}

public String toString(){

return "Employee String"

}

When I call employee.callSuperToString() then something like Employee@10b62c9 is printed since it is calling the Object class toString method . The super.toString is not called on Employee instance.

Similar situation is here also. What say?

Nandan.Srivastavaa at 2007-7-10 11:37:28 > top of Java-index,Java Essentials,Java Programming...
# 5
You have the Clone method declared, as your class is extending from Object.MeTitus
Me_Titusa at 2007-7-10 11:37:28 > top of Java-index,Java Essentials,Java Programming...
# 6

I got it.

It is the e.g of getClass().getName() which helped me to understand. May be the best e.g possible but it was not very obvious in the beginning to me.

I think it is the implementation of clone method in Object class which is responsible to returning an object of type Employee.

Thanks guys.

Nandan.Srivastavaa at 2007-7-10 11:37:28 > top of Java-index,Java Essentials,Java Programming...
# 7

> When I call employee.callSuperToString() then

> something like Employee@10b62c9 is printed since it

> is calling the Object class toString method . The

> super.toString is not called on Employee instance.

> Similar situation is here also. What say?

No it is calling Employee.toString().

MeTitus

Me_Titusa at 2007-7-10 11:37:28 > top of Java-index,Java Essentials,Java Programming...
# 8
Just a note:be carefully with cloning if your Employee object has references to other objects (e.g., arrays) because in this cases the clone method duplicates the references to this objects, and in this cases you should improve your clone() method.Manuel Leiria
manuel.leiriaa at 2007-7-10 11:37:28 > top of Java-index,Java Essentials,Java Programming...
# 9

> When I call employee.callSuperToString() then

> something like Employee@10b62c9 is printed since it

> is calling the Object class toString method . The

> super.toString is not called on Employee instance.

> Similar situation is here also. What say?

Don't think about "employee.callSuperToString()" in terms of "calling a method," think about it in terms of sending a message to an object.

When the employee object receives the message "callSuperToString," it reacts by executing the method with the same name. While executing the method, the employee object sends another message, "super.toString()," to itself. The reaction to this message is the execution of the toString method of the super class; not of the Employee class. Even though the code executed can come from the Employee class or any of its super classes there's only one object involved.

One way to convince yourself that you only have one object is making your overriding toString method include the hash code of the object. The hash code is what you see after the @-sign in the output from the toString method of the Object class. It's as unique an identifier of the object as possible, so if the hash codes or two objects are the same it's very likely they are the same object, unless you have overridden the hashCode method.

public String toString(){

return "Employee with hash code " + Integer.toHexString(hashCode());

}

jsalonena at 2007-7-10 11:37:28 > top of Java-index,Java Essentials,Java Programming...
# 10

> Just a note:

>

> be carefully with cloning if your Employee object

> has references to other objects (e.g., arrays)

> because in this cases the clone method duplicates the

> references to this objects, and in this cases you

> should improve your clone() method.

>

> Manuel Leiria

Hi Manuel say I have:

Public class Employee implements Cloneable

{

ArrayList obj = new ArrayList();

}

Employee emp = new Employee();

Employee emp1 = emp.clone();

How many instances of obj will I have in emp1 , 2?

MeTitus

Me_Titusa at 2007-7-10 11:37:28 > top of Java-index,Java Essentials,Java Programming...
# 11
I read something about cloning a method once, and according to the author the best practice was to implement the clone method rather the using the native one.MeTitus
Me_Titusa at 2007-7-10 11:37:28 > top of Java-index,Java Essentials,Java Programming...
# 12
> the best practice was to implement the clone method > rather the using the native one.This method of Object is protected and serves as an implementation help for user-defined classes with their own (possibly public) clone() method.
BIJ001a at 2007-7-10 11:37:28 > top of Java-index,Java Essentials,Java Programming...
# 13

Public class Employee implements Cloneable

{

ArrayList obj = new ArrayList();

}

Employee emp = new Employee();

Employee emp1 = emp.clone();

//How many instances of obj will I have in emp1 , 2?

Two.

protected Object clone() throws CloneNotSupportedException

/*

Creates and returns a copy of this object.

The precise meaning of "copy" may depend on the class of the object.

The general intent is that, for any object x, the expression will be true:

*/

x.clone() != x

BIJ001a at 2007-7-10 11:37:28 > top of Java-index,Java Essentials,Java Programming...
# 14
Thanks BIJ001 ;)MeTitus
Me_Titusa at 2007-7-10 11:37:28 > top of Java-index,Java Essentials,Java Programming...
# 15

> > Public class Employee implements Cloneable

> {

>ArrayList obj = new ArrayList();

>

> mployee emp = new Employee();

>

> mployee emp1 = emp.clone();

>

> /How many instances of obj will I have in emp1 , 2?

>

>

>

> Two.

>

> > protected Object clone() throws

> CloneNotSupportedException

> /*

> Creates and returns a copy of this object.

> The precise meaning of "copy" may depend on the class

> of the object.

> The general intent is that, for any object x, the

> expression will be true:

> */

> x.clone() != x

Don't be so sure!

Check this sample:

public class Employee implements Cloneable {

public ArrayList obj;

public Employee(){

obj = new ArrayList();

}

public Object clone() {

try {

return (Employee) super.clone();

} catch (CloneNotSupportedException e) {

throw new InternalError(e.toString());

}

}

}

and now let's clone,

public class Starter {

public static void main(String[] args) {

//First object

Employee emp1 = new Employee();

emp1.obj.add("Hello from emp1"); //ArrayList obj from emp1

//And the clone

Employee emp2 = (Employee)emp1.clone();

emp2.obj.add("Hello from emp2");//ArrayList obj from the clone

for(int i = 0; i < emp1.obj.size(); i++){

//Let's check the contents of ArrayList from emp1

System.out.println((String)emp1.obj.get(i));

}

}

}

OUTPUT:

Hello from emp1

Hello from emp2

that is the clone has a reference to the same ArrayList as the original!

Workaround: improve the clone method:

public Object clone() {

try {

Employee nObj = (Employee) super.clone();

nObj.obj = (ArrayList)obj.clone();

return nObj;

} catch (CloneNotSupportedException e) {

throw new InternalError(e.toString());

}

}

Running again with this new clone method we have:

OUTPUT:

Hello from emp1

Manuel Leiria

manuel.leiriaa at 2007-7-21 18:47:32 > top of Java-index,Java Essentials,Java Programming...
# 16
Thats why the clone method should be implemented according to what one needs, the clone method provided by the Object class is not suitable for all the needs.MeTitus
Me_Titusa at 2007-7-21 18:47:32 > top of Java-index,Java Essentials,Java Programming...