2009-09-03 6 views
2

J'ai une classe de base, disent Base qui spécifie la méthode abstraite deepCopy, et une myriade de sous-classes, dites A, B, C ... Z. Comment puis-je définir deepCopy afin que sa signature soit public X deepCopy() pour chaque classe X?Comment implémenter le clonage profond générique de type sécurisé dans une hiérarchie de classes Java?

Bon, maintenant, je:

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

Malheureusement, cela signifie que si si j'ai un objet d'une sous-classe, dire a de A, alors je dois toujours effectuer une distribution non contrôlée pour une plus copie profonde spécifique:

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

Y at-il un moyen, peut-être en utilisant des génériques, pour éviter de lancer? Je veux garantir que toute copie en profondeur renvoie un objet de la même classe d'exécution. Edit: Permettez-moi d'étendre ma réponse car le typage covariant n'est pas suffisant. Dire, je voulais ensuite mettre en œuvre une méthode comme:

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; 
    } 

Comment puis-je éviter l'avertissement non contrôlé?

+0

Il y a quelques utilitaires qui feront cela pour vous ... http://www.genericdeepcopy.com/ et http://code.google.com/p/cloning/. – Aaron

Répondre

5

Java 5 prend en charge les types de retour covariant, ce qui signifie que vous pouvez implémenter votre méthode deepCopy() dans chaque sous-classe pour renvoyer l'instance de sous-classe spécifique; par exemple.

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

    } 
} 

Plus sur les types de retour covariant here.

+0

Merci! Je suppose que vous avez répondu à ma question initiale, mais je n'ai pas tout à fait résolu mon problème. :-) – namin

2

C'est vraiment pas assez, et je ne serait probablement pas le faire moi-même, mais:

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; 
    } 
} 

Ou ....

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; 
    } 
} 
+0

+1, c'est le seul moyen de spécifier qu'une sous-classe doit retourner un objet de son propre type. –

1

Que diriez-vous ...

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

Alors ... par exemple ... (avec erreurs, mais bonnes intentions, aide!)

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; 
    } 
} 
Questions connexes