How to implement generic deep type cloning in a Java class hierarchy?

I have a base class, for example Base

, which indicates an abstract method deepCopy

and many subclasses, eg A

, B

, C

, ... Z

. How to define deepCopy

so that its signature public X deepCopy()

for each class X

?

Now I have:

abstract class Base {
  public abstract Base deepCopy();
}

      

Unfortunately, this means that if I have an object from a subclass, say A

of A

, then I always need to do an unchecked cast for a more specific deep copy:

A aCopy = (A) a.deepCopy();

      

Is there a way, perhaps to use generics to avoid casting? I want to ensure that any deep copy returns an object of the same runtime class.

Edit: Let me extend my answer since covariant input is not enough. Let's say I then wanted to implement a method like:

static <N extends Base> List<N> copyNodes(List<N> nodes) {
    List<N> list = Lists.newArrayList();
    for (N node : nodes) {
      @SuppressWarnings("unchecked")
      N copy = (N) node.deepCopy();
      list.add(copy);
    }
    return list;
  }

      

How can I avoid the unverified warning?

+2


source to share


3 answers


Java 5 supports covariant return types, which means that you can implement your method deepCopy()

in each subclass to return a specific instance of the subclass; eg.

public class Z extends Base {
  @Override
  public Z deepCopy() {

  }
}

      



Read more about covariant return types here .

+5


source


It's really not pretty, and I probably wouldn't do it myself, but:

    public abstract class Base<T extends Base<T>> {
    public abstract T deepCopy();
}
public class Extender extends Base<Extender> {

    @Override
    public Extender deepCopy() {
        // TODO Auto-generated method stub
        return null;
    }
}

      



Or....

    public abstract class Base<T extends Base<T>> {
    public abstract T deepCopy();
}
public class Extender<T extends Base<T>> extends Base<T> {

    @Override
    public T deepCopy() {
        // TODO Auto-generated method stub
        return null;
    }
}

      

+2


source


What about...

public interface DeeplyCloneable <T extends Cloneable> {
    public T deepClone();
}

      

Then ... for example ... (erroneous but well-intentioned, help!)

public class DeeplyClonableHashTable

         <T1 extends DeeplyCloneable<?>,T2 extends DeeplyCloneable<?>> 
extends Hashtable<T1,T2>
implements DeeplyCloneable<Hashtable<T1,T2>>{

@Override
public Hashtable<T1, T2> deepClone() {
  Object o = super.clone();
  if ((o == null) || (! (o instanceof DeeplyClonableHashTable<?,?>)))
  {
    throw new DeepCloneException(
      "Object instance does not support deepCloneing.");
  }

  @SuppressWarnings("unchecked")
  DeeplyClonableHashTable<T1,T2> copy = (DeeplyClonableHashTable<T1,T2>)o;
  Set<T1> keys = copy.keySet();

  for (T1 key: keys){
    T2 value = this.get(key);
    T1 keyCopy = key.deepClone();  // this line is in error
    T2 valueCopy = value.deepClone();  // this line is in error
    copy.put(keyCopy, valueCopy);
  }
  return copy;
  }
} 

      

+1


source







All Articles