2013-08-09 7 views
10

Mi chiedo se esiste un modo per eseguire quanto segue. Ho una classe astratta, Shape, e tutte le sue sottoclassi diverse e voglio sovrascrivere il metodo clone. Tutto quello che voglio fare nel metodo è creare un nuovo Shape dal toString() di quello corrente. Ovviamente non posso fare quanto segue perché Shape è astratto. C'è un altro modo per farlo perché il clone di override in ogni sottoclasse solo per un semplice cambio di nome sembra inutile.Oggetti astratti di clonazione Java

public abstract class Shape { 

    public Shape(String str) { 
     // Create object from string representation 
    } 

    public Shape clone() { 
     // Need new way to do this 
     return new Shape(this.toString()); 
    } 

    public String toString() { 
     // Correctly overriden toString() 
    } 
} 
+1

Utilizzare la riflessione? – johnchen902

risposta

5

Si può provare a utilizzare la riflessione:

public abstract class AClonable implements Cloneable{ 

private String val; 

public AClonable(){ 

} 

public AClonable(String s){ 
    val=s; 
} 

public String toString(){ 
    return val; 
} 

@Override 
public AClonable clone(){ 
    try { 
     System.out.println(getClass().getCanonicalName()); 
     AClonable b= getClass().getDeclaredConstructor(String.class).newInstance(val); 

     return b; 
    } catch (InstantiationException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IllegalAccessException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IllegalArgumentException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (SecurityException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (InvocationTargetException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (NoSuchMethodException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    return null; 
} 

}

nel metodo clone() si chiama getClass(). Poiché l'ACloneble è astratto, il richiamo andrà sempre alla classe concreta.

public class ClonebaleOne extends AClonable{ 

public ClonebaleOne(){ 
    super(); 
} 

public ClonebaleOne(String s) { 
    super(s); 
    // TODO Auto-generated constructor stub 
} 

}

e

public class ClonebaleTwo extends AClonable{ 

public ClonebaleTwo(){ 
    super(); 
} 

public ClonebaleTwo(String s) { 
    super(s); 
    // TODO Auto-generated constructor stub 
} 

}

e infine

public static void main(String[] args){ 
    AClonable one = new ClonebaleOne("One"); 
    AClonable tow= new ClonebaleTwo("Two"); 
    AClonable clone = one.clone(); 
    System.out.println(clone.toString()); 
    clone = tow.clone(); 
    System.out.println(clone.toString()); 

} 

uscita:

ClonebaleOne 
    One 
    ClonebaleTwo 
    Two 

ma è più un hack che una soluzione

[EDIT] i miei due cloni sono stati più veloci rispetto;)

[EDIT] per essere completa. Un altro implentation di clone() può essere

@Override 
public AClonable clone(){ 
    try { 
     ByteArrayOutputStream outByte = new ByteArrayOutputStream(); 
     ObjectOutputStream outObj = new ObjectOutputStream(outByte); 
     ByteArrayInputStream inByte; 
     ObjectInputStream inObject; 
     outObj.writeObject(this); 
     outObj.close(); 
     byte[] buffer = outByte.toByteArray(); 
     inByte = new ByteArrayInputStream(buffer); 
     inObject = new ObjectInputStream(inByte); 
     @SuppressWarnings("unchecked") 
     Object deepcopy = inObject.readObject(); 
     inObject.close(); 
     return (AClonable) deepcopy; 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 

quando la classe astratta implementa Serialazable. Lì scrivi il tuo oggetto su disco e crei una copia con il valore del disco.

+0

Mi piace la tua idea e forse mi tornerà utile in futuro, ma penso che starò meglio definendo il clone per ogni sottoclasse. Peccato che non ci sia un modo più semplice per raggiungere questo obiettivo. – negoose

+0

Per definirli in ogni sottoclasse è la soluzione migliore in modo orientato agli oggetti. Sono d'accordo con sanbhat. Temo che la soluzione Serialazable sia la più lenta ed è anche un hack. –

2

Non è possibile creare profondo clone di abstract classe perché non possono essere istanziati. Tutto si può fare è superficiale clonazione utilizzando Object.clone() o di ritorno this

@Override 
public Object clone() throws CloneNotSupportedException { 
    return super.clone(); 
} 

o

@Override 
public Object clone() throws CloneNotSupportedException { 
    return this; 
} 

Una classe astratta può agire come un punto di riferimento, e non può avere un caso così superficiale clonazione funziona questo caso

O

Come un approccio migliore, è possibile dichiarare clone() come abstract e chiedere classe figlio di definirlo, qualcosa di simile

abstract class Shape { 

    private String str; 

    public Shape(String str) { 
     this.str = str; 
    } 

    public abstract Shape clone(); 

    public String toString() { 
     return str; 
    } 
} 

class Circle extends Shape { 

    public Circle(String str) { 
     super(str); 
    } 

    @Override 
    public Shape clone() { 
     return new Circle("circle"); 
    } 

} 
1

Anche se dubito che sia una buona idea, si potrebbe utilizzare la riflessione:

import java.lang.reflect.Constructor; 
import java.lang.reflect.InvocationTargetException; 

public class Test { 

    public static void main(String[] args) {   
     Square s1 = new Square("test"); 
     Square s2 = (Square) s1.clone(); 

     // show that s2 contains the same data 
     System.out.println(s2); 
     // show that s1 and s2 are really different objects 
     System.out.println(s1 == s2); 
    } 

    public static abstract class Shape { 
     private String str; 

     public Shape(String str) { 
      this.str = str; 
     } 

     public Shape clone() {   
      try { 
       Class<?> cl = this.getClass(); 
       Constructor<?> cons = cl.getConstructor(String.class); 
       return (Shape) cons.newInstance(this.toString());   
      } catch (NoSuchMethodException | SecurityException | 
        InstantiationException | IllegalAccessException | 
        IllegalArgumentException | InvocationTargetException e) { 
       e.printStackTrace(); 
      }   

      return null; 
     } 

     @Override 
     public String toString() { 
      return str; 
     } 
    } 

    public static class Square extends Shape { 
     public Square(String str) { 
      super(str); 
     } 
    } 
} 
1

È possibile risolvere con la riflessione:

public abstract class Shape { 

    private String str; 

    public Shape() { 

    } 

    protected Shape(String str) { 
     this.str = str; 
    } 

    public Shape clone() throws CloneNotSupportedException 
    { 
     try { 
      return (Shape)getClass().getDeclaredConstructor(String.class).newInstance(this.toString()); 
     } catch (Exception e) { 
      throw new CloneNotSupportedException(); 
     } 
    } 

    public String toString() { 
     return "shape"; 
    } 

public class Round extends Shape 
{ 
    public Round() 
    { 
     super(); 
    } 
    protected Round(String str) { 
     super(str); 
    } 

    @Override 
    public String toString() { 
     return "round"; 
    } 
} 

main(){ 
    Shape round = new Round();   
    Shape clone = round.clone(); 
    System.out.println(round); 
    System.out.println(clone); 
} 

ma - IMO - è una cattiva implementazione e soggetta a errori con un sacco di pit; il miglior uso di Cloneable e Object.clone() è di non usarli! Hai un sacco di modi per fare la stessa cosa (come la serializzazione per clone profondo) e il clone superficiale che ti permettono un migliore controllo del flusso.