Возможно, есть много решений для этого случая, но я полагаю, что самым простым было бы использование отражения для создания клонированного объекта и копирования полей из оригинала в копию.Единственное требование этого кода состоит в том, что ваши подклассы должны иметь конструктор по умолчанию, но в любом случае это не выглядит настоящей проблемой.
Вот как это будет выглядеть:
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);
}
}
}
А вот ваш подкласс, в котором не было бы ничего особенного:
public class Saw extends Tool {
private int weight;
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
И тестовый пример JUnit, показывающий, как он будет работать:
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() );
}
}