2012-11-15 18 views
5

Ho improvvisamente riscontrato un problema nel creare una copia polimorfica profonda in Java. L'implementazione Clonable risolve il problema nel mio caso, ma viene spesso definito come una tecnica "cattiva".Copia polimorfa in Java

Così, qui sono i miei tentativi di trovare un "no-clonabile" Soluzione:

public class Parent { 
    int x; 

    public Parent() {} 

    public Parent(int x0) { 
     x = x0; 
    } 

    public Parent copy() { 
     Parent b = new Parent(); 
     b.assign(this); 

     return b; 
    } 

    protected void assign(Parent c) { 
     x = c.x; 
    } 

    @Override 
    public String toString() { 
     return getClass().getName() + ", " + x; 
    } 
} 

public class Child extends Parent { 
    int y; 

    protected Child() {} 

    public Child(int x0, int y0) { 
     super(x0); 
     y = y0; 
    } 

    @Override 
    public Child copy() { 
     Child b = new Child(); 
     b.assign(this); 

     return b; 
    } 

    @Override 
    protected void assign(Child c) { 
     super.assign(c); 
     y = c.y; 
    } 

    @Override 
    public String toString() { 
     return getClass().getName() + ", " + x + "," + y; 
    } 
} 

public class Test { 
    public static void main(String[] args) { 
     Parent x = new Parent(5); 
     Child y = new Child(10, 20); 
     Parent z = x.copy(); 
     Parent w = y.copy(); 

     System.out.println(x); 
     System.out.println(y); 
     System.out.println(z); 
     System.out.println(w); 
    } 
} 

l'output è:

com.xxx.zzz.Parent, 5 
com.xxx.zzz.Child, 10,20 
com.xxx.zzz.Parent, 5 
com.xxx.zzz.Child, 10,20 

e un altro modo (più breve) di fare lo stesso (utilizzando Riflessione):

public class Parent { 
    int x; 

    public Parent() {} 

    public Parent(int x0) { 
     x = x0; 
    } 

    public Parent copy() { 
     try { 
      Parent b = getClass().newInstance(); 
      b.assign(this); 
      return b; 
     } catch (InstantiationException | IllegalAccessException e) { 
      e.printStackTrace(); 
      return null; 
     } 
    } 

    protected void assign(Parent c) { 
     x = c.x; 
    } 

    @Override 
    public String toString() { 
     return getClass().getName() + ", " + x; 
    } 
} 

public class Child extends Parent { 
    int y; 

    protected Child() {} 

    public Child(int x0, int y0) { 
     super(x0); 
     y = y0; 
    } 

    protected void assign(Child c) { 
     super.assign(c); 
     y = c.y; 
    } 

    @Override 
    public String toString() { 
     return getClass().getName() + ", " + x + "," + y; 
    } 
} 

Non c'è bisogno di sovrascrivere copy() nella classe Child. Ma non sono sicuro di quanto sia "legale" utilizzare getClass(). NewInstance() per costruire un segnaposto di copia ...

Le soluzioni sopra valgono la pena o ci sono approcci più comuni/robusti/semplici?

Grazie!

+0

Questo non funziona se 'Bambino' ha un costruttore predefinito. –

risposta

2

La soluzione sembra a posto per me, per questo particolare caso d'uso.

Le principali limitazioni di utilizzo newInstance(), sono che:

  • funziona solo con oggetti che hanno un costruttore no-arg, e
  • sarebbe in grado di clonare oggetti che hanno campi finali

Esistono alcune librerie che supportano la clonazione. Dai uno sguardo allo Kryo. È una libreria di serializzazione che supporta anche la clonazione (profonda e superficiale), inclusi gli oggetti senza costruttori no-arg o che hanno campi finali.

0

Non sono mai stato un grande fan dell'approccio "clone()". Copiare i costruttori sembrano essere più elegante IMO:

public class Parent { 
    int x; 

    public Parent() { 
     super(); 
    } 

    public Parent(Parent other) { 
     super(); 
     this.x = other.x; 
    } 
} 

public class Child extends Parent { 
    int y; 

    public Child() { 
     super(); 
    } 

    public Child(Child other) { 
     super(other); 
     this.y = other.y; 
    } 
} 

Nota, questo ha anche il vantaggio di essere in grado di farlo se è necessario:

Parent p = new Parent(new Child(...)); 

Si potrebbe ovviamente impedire che il comportamento in il costruttore controllando il tipo di classe concreto dell'argomento , ma non vedo perché dovresti farlo nella maggior parte dei casi.

+1

Il problema è che i costruttori di copie non gestiscono correttamente il polimorfismo – user671786

Problemi correlati