I try to use a simple example for better undersanding: I've got a class Tool
and child classes which are extending class Tool
: Hammer
, Saw
. Both have defined some fields like weight
and both are overriding method getCost
with own implementation.
Tool first_tool = new Hammer();
Tool second_tool = new Saw();
I need a method in Tool
class, that will to do a copy of any tool, such way, that first_tool_copy
is from the same subclass as first_tool
. How can I make this possible? I need something like:
/* Copy tool, change parameters of copy, the original won't change */
/* first_tool_copy will be instance of Hammer class */
first_tool_copy = first_tool.copy
first_tool_copy.weight = 100
Conclusions: I would like to have some simple copy constructor common for all subclasses.
There are possibly many solutions for this case, but I believe the simplest one would be using reflection to create the cloned object and copy the fields from the original to the copy. The only requirement this code has is that your subclasses must have a default constructor, but this doesn't look like a real issue anyway.
Here's how it would look like:
And here's your subclass, that would not have anything special:
And a JUnit test case showing how it would work:
If you don't want a specific copy for all the subclasses (what is fair enough), you have to use reflection. And if you are ok using reflection, you may want to use BeanUtils.
I would have a utility class, say CopyUtil and a copy method in it to copy an object (using BeanUtils). For some reason if you need the copy method as an instance method of Tool, just write one and call this utility method from there.
I'd just like to build off of the first part of Matt Ball's answer and mention that, since Java 5, return type covariance is supported. What this means is that a child class can override a method by returning a more specific type. This would allow you to do the following:
So, when you're working with an assortment of
Tool
objects, you know you can callcopy()
and getTool
back. When you're working with onlyHammer
objects, you knowcopy()
will return aHammer
(cast is not required).I would make
Tool
abstract, and add anabstract copy
method toTool
. Then each subclass is forced to provide its own implementation. This is a fairly OO approach, and takes advantage of dynamic dispatch.Otherwise, you'd provide a concrete implementation in
Tool
which you'd have to update every time to want to handle a new subclass ofTool
. This method would have to useinstanceof
,getClass()
, or similar non-OO techniques to create the right class. Ew.Remember what Effective Java Item 10 tells us: Override
clone
judiciously.Assuming the
Tool
implementation looks something like the below class, you could do this with reflection:I wouldn't recommend this, though. It's just smelly and ugly to me.