In this case, many solutions are possible, but I believe that the simplest one will use reflection to create a 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 in any case, this does not seem like a real problem.
Here's how it would look:
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 is 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 sample JUnit test showing how it will 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() ); } }
source share