• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Question regarding Cloneable interface and Subclasses

 
Ranch Hand
Posts: 58
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi everyone,

I'm reading through Core Java Volume 1 (8th Ed.) and I came across the section on the Cloneable Interface (Chapt 6, page 253). The author gives an example of an Employee Class that implements Cloneable and writes an overriding public Employee clone() method that performs a deep copy of the Employee object. There is also another simple Manager Class that extends Employee and has an additional field named bonus of a basic type (double). The author then says the following:
"You have to be careful about cloning of subclasses. For example, once you have defined the clone method for the Employee class, anyone can use it to clone Manager objects. Can the Employee clone method do the job? It depends on the fields of the Manager class. In our case, there is no problem because the bonus field has primitive type."

However, it struck me that there is a slight problem because if I tried to clone a Manager object, I would get a clone by virtue of the clone() method specified in the Employee class. While this would still do a perfectly fine job of performing a shallow copy of the original Manager object, it would return an object of type Employee when I would normally expect a clone operation to return an object of the same type as that being cloned.

So I went ahead and tried writing the code and running it (see below), and it gave me an error unless I recast the cloned object as follows:


Personally, it seems like a bad idea to rely on inheritance for the implementation of the clone method because as in this case, you won't be sure of the actual Object type that you will be getting back when you perform a clone operation. On the other hand, it seems it might be tedious to always rewrite the clone method for each subclass of a class that implements Cloneable, just to ensure that the clone method for each class/subclass returns the correct object type.

So I was wondering what is the recommended approach? Should I either re-cast the object from a clone() method call at all times to prevent such a situation or should I ensure that a clone() method returning the apt object type is always provided for all classes that implement or inherit Cloneable?

 
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ryan Sykes wrote:
However, it struck me that there is a slight problem because if I tried to clone a Manager object, I would get a clone by virtue of the clone() method specified in the Employee class. While this would still do a perfectly fine job of performing a shallow copy of the original Manager object, it would return an object of type Employee



Yes. And that object is also of type Object, and it is also of type Manager, and it is also of type Cloneable. In other words, it's a copy of the original object, and it's the same class as the original object.

So I went ahead and tried writing the code and running it (see below), and it gave me an error unless I recast the cloned object as follows:



Yup. The clone() method is declared to return either Object or Employee, depending on how you declared it in Employee. And the fact that casting works proves that it's a Manager, not just an Employee. (Casting never changes an object. It just tells the compiler and the JVM to treat a reference that's declared to be of type X as if it were actually of type Y.)


Personally, it seems like a bad idea to rely on inheritance for the implementation of the clone method because as in this case, you won't be sure of the actual Object type that you will be getting back



There's nothing special about clone() here. Just like any other method, you have to return the type you declare, and you can always return a subtype, but there's no guarantee the implementer of the method will write it do to what the docs say it does, or to return the type you expect.

For instance, one incorrect way that people implement clone() is like so:


If clone were implemented like that, then Manager's clone() method would not return a Manager. But calling super.clone() always produces the same class as the original.

Before 1.5 or 1.6, there were no covariant return types, so every overriding method had to declare to return exactly the same type as its parent's method. So clone() had to return object. Now, implementing clone() in class X, we can declare to return X or any supertype of X. (Or any subtype, for that matter, but that would be a bad idea.)

Previously, we always had to cast after clone(), and one X overrode it, there was no advantage to any subclass overriding it, if it didn't have to deep clone any additional fields. Now, however, even if we don't change anything in subclasses, the (small) benefit of re-overriding clone is that we don't have to cast.
 
Ranch Hand
Posts: 144
MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Clone method is of type Employee & original instance is of type Manager which is a subclass of Employee so type casting is required otherwise it would be a mismatch. So for compiler to understand explicit casting is required.

Hope this helps.
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Zeeshan Sheikh wrote:
Clone method is of type Employee & original instance is of type Manager which is a subclass of Employee so type casting is required otherwise it would be a mismatch. So for compiler to understand explicit casting is required.

Hope this helps.



The problem is that the OP mistakenly thought that the object produced was just an Employee, not a Manager.
 
Ryan Sykes
Ranch Hand
Posts: 58
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jeff Verdegan wrote:

Zeeshan Sheikh wrote:
Clone method is of type Employee & original instance is of type Manager which is a subclass of Employee so type casting is required otherwise it would be a mismatch. So for compiler to understand explicit casting is required.

Hope this helps.



The problem is that the OP mistakenly thought that the object produced was just an Employee, not a Manager.



Thanks for your responses Jeff and Zeeshan. Perhaps I should have worded my question better. I did understand why type casting was necessary and that the object being returned was still of actual type Manager, even though it had a declared return type of Employee (making the explicit casting necessary). However, my concern was more to do with what one actually expects a generic clone method in a class that implements or inherits the Cloneable interface to return.

For example, I would think that if I had no prior knowledge of how cloneable was implemented in Employee and Manager classes (just that both of them implement cloneable), then I would expect that:

would work, and original.clone() would return a copy of the object with type Employee.

I would naively think should also work (if I did not know how Manager actually inherits the clone() method).

However, obviously the second case fails because of the way clone() is inherited from Employee, where the return type is declared to be of type Employee. So my confusion has to do with whether there is any "Standard" that is defined for what the return type of a clone() method call should be? Is the standard that instanceOfClassA.clone() should return a copy of declared type A? or is it that there are no assurances about what the type of the returned copy will be?...just that it could be of type A, or a superclass of A (that also implements/inherits Cloneable).

It seems a little inelegant to me that the return type of a clone() method call on an Object of actual type A doesn't guarantee that you get back a copy of the object of declared type A (although it obviously is still actually of type A and can be reobtained using explicit casting). That is why I was wondering whether we should strive to write custom clone() methods for each subclass that inherits the clone() method from a superclass, to ensure that the clone method on the subclass returns a copy with declared type of the subclass. For example:

The above code would ensure that calling the clone() method on a Manager object would assure me a copy with declared type Manager. This seems like it would make the code more intuitive because otherwise, the fact that in one case I have to explicitly cast the returned copy (for Manager) and not for the other (for Employee) seems a little inelegant *to me* since I would think that one would want a similar behaviour from the same method call for 2 classes that implement or inherit the same method.

To perhaps re-frame my question...is the declared type of the returned copy part of the "Contract" established by a class inheriting/implementing the Cloneable interface?
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ryan Sykes wrote:my concern was more to do with what one actually expects a generic clone method in a class that implements or inherits the Cloneable interface to return.



I expect it to return the same class as the original object. And it does. And, knowing how Java works, without regard to clone() in particular, I wouldn't expect to get a reference of a subclass type without casting unless the subclass overrides the method itself.

For example, I would think that if I had no prior knowledge of how cloneable was implemented in Employee and Manager classes (just that both of them implement cloneable), then I would expect that:

would work, and original.clone() would return a copy of the object with type Employee.

I would naively think should also work (if I did not know how Manager actually inherits the clone() method).



If Manager overrides it, yes, I would expect that too. But I was under the impression you were talking about Employee overriding it and Manager inheriting from Employee. In that case, you would be naive indeed to expect to get a Manager without casting, and, again, that's nothing to do with clone() in particular.

For instance, List has a subList() method that returns List. Would you expect to call that on an ArrayList and be able to use the result as an ArrayList without a cast (even if the returned type were guaranteed to be the same type as the original List, which I don't think it is)? If so, can you please specify, clearly and precisely--preferably by citing the JLS--what part of the language would make that possible?

Or, for that matter, can you write a method other than clone() that behaves the way you're saying clone() should behave?

 
Ryan Sykes
Ranch Hand
Posts: 58
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jeff Verdegan wrote:
I expect it to return the same class as the original object. And it does. And, knowing how Java works, without regard to clone() in particular, I wouldn't expect to get a reference of a subclass type without casting unless the subclass overrides the method itself.


Okay, that makes sense.

Jeff Verdegan wrote:
For instance, List has a subList() method that returns List. Would you expect to call that on an ArrayList and be able to use the result as an ArrayList without a cast (even if the returned type were guaranteed to be the same type as the original List, which I don't think it is)? If so, can you please specify, clearly and precisely--preferably by citing the JLS--what part of the language would make that possible?

Or, for that matter, can you write a method other than clone() that behaves the way you're saying clone() should behave?


Good point Jeff. I haven't gotten to Generics yet...so I was hoping there might be some magic there that could be used to make clone() behave the way I was thinking it should, or hoping it should, when inherited from a parent class . I certainly don't know how that would be possible (and it seems it isn't, unless I override the method as in my previous post) but it felt like that would be nice if it did, as it would make the clone() method feel more consistent when it is inherited from a parent class. However, seeing as that isn't the case, I do understand why I would need to explicitly cast the returned object, and that makes sense.

As a final clarification...am I missing some finer/subtle point regarding polymorphism/inheritance as to why it would be better for the inherited clone() method to return a cloned object of declared type of the superclass or is it just a limitation (perhaps too strong a word) of the JLS and tools available for defining a method? Am I giving some flexibility up by writing my own clone() method for the Manager class and declaring the return type as Manager()? If not, is there a best practice or recommendation as to whether one should always override the clone method as I listed earlier, or is it entirely up to us to either use the inherited clone method and explicitly cast the returned object or write a custom clone method for the subclass?

Thanks for your patience and for all your help. I really appreciate it!

PS - Just thought of this... would this work? return (getClass()) super.clone();
Is it possible to query the object Class and then cast the returned object this way? I assume the compiler would probably throw a fit over something like this as it would have no ability to determine what getClass() would return till runtime .
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ryan Sykes wrote:
Good point Jeff. I haven't gotten to Generics yet...so I was hoping there might be some magic there that could be used to make clone() behave the way I was thinking it should,



I always have to think about this situation a bit, and I don't feel like doing that thinking now. so off the top of my head, but possibly not exactly correct, it could probably be done: A) If Object were declared Object<T>, and that T was always the actual class, and clone returned T, or 2) If clone() had a <T> type arg and took Class<T> as an arg. Either way, it would probably be messier than just casting, and might break pre-generics code.

As a final clarification...am I missing some finer/subtle point regarding polymorphism/inheritance as to why it would be better for the inherited clone() method to return a cloned object of declared type of the superclass



Not sure what you're saying here. If Parent extends Object, and Parent is Cloneable, then Parent.clone() should be declared to return Parent. If Child extends Parent, then, because Parent is Cloneable, Child is also Cloneable. If Child doesn't override Parent's clone(), then the clone() method that we call will return a Child object, but, since it's implemented in Parent, it's declared to return Parent.

Now, we certainly could override clone() in Child, declare it to return Child, so that we don't have to cast.

PS - Just thought of this... would this work? return (getClass()) super.clone();



No. The object is still the same type as the original, and the declared type is still the parent type.
 
Ryan Sykes
Ranch Hand
Posts: 58
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for the reply Jeff. I'll try to see if it is possible once I learn about generics. Perhaps it is possible to implement using generics, but as you mentioned, it would then break compatibility with older code before generics were introduced.

If Child doesn't override Parent's clone(), then the clone() method that we call will return a Child object, but, since it's implemented in Parent, it's declared to return Parent.

Now, we certainly could override clone() in Child, declare it to return Child, so that we don't have to cast.


Yup, that makes sense. If this is indeed implementable with Generics (or some other method), I was wondering if there was a specific reason why clone() was implemented as it is, so it returns a declared type of the Parent from a subclass that inherits the clone() method. But now it seems clear that perhaps it was more a limitation of how a method could be defined originally which might perhaps be fixable with Generics, but even if it were so, would break compatibility with older code, so it is not implemented in that manner.

I guess if it is possible to implement the clone() method like I was hoping using Generics, then it might make sense to define clone() in that way, so the inheriting subclasses end up returning cloned objects of declared type corresponding to the subclass, thus doing away with the need for explicit casts.

Thanks for all the help!
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic