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.
Objects from subclasses can be stored in the same array of the parent type.
A subclass inherits all the members (fields, methods, and nested classes) from its superclass. Constructors are not members, so they are not inherited by subclasses, but the constructor of the superclass can be invoked from the subclass.
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:
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Tool implements Cloneable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public Object clone() {
try {
Tool instance = this.getClass().newInstance();
List<Field> fields = new ArrayList<Field>();
Class<?> kind = this.getClass();
while ( kind != null ) {
fields.addAll( Arrays.asList( kind.getDeclaredFields() ) );
kind = kind.getSuperclass();
}
for ( Field field : fields ) {
field.setAccessible(true);
int mod = field.getModifiers();
if ( !Modifier.isStatic( mod ) && !Modifier.isFinal( mod ) && !Modifier.isNative(mod) ) {
Object value = field.get( this );
field.set(instance, value);
}
}
return instance;
} catch (Exception e) {
throw new UnsupportedOperationException(e);
}
}
}
And here's your subclass, that would not have anything special:
public class Saw extends Tool {
private int weight;
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
And a JUnit test case showing how it would work:
public class SawTest {
@Test
public void testClone() {
Saw original = new Saw();
original.setName("Some saw");
original.setWeight( 10 );
Saw clone = (Saw) original.clone();
Assert.assertTrue( original != clone );
Assert.assertTrue( original.getClass().equals( clone.getClass() ) );
Assert.assertEquals( original.getName(), clone.getName() );
Assert.assertEquals( original.getWeight(), clone.getWeight() );
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With