2013-08-09 10 views
10

Ich frage mich, ob es eine Möglichkeit gibt, das Folgende zu tun. Ich habe eine abstrakte Klasse, Shape, und alle ihre verschiedenen Unterklassen, und ich möchte die Klonmethode überschreiben. Alles, was ich in der Methode tun möchte, ist eine neue Shape aus der toString() der aktuellen erstellen. Offensichtlich kann ich folgendes nicht tun, weil Shape abstrakt ist. Gibt es eine andere Möglichkeit, dies zu tun, da das Überschreiben von Klonen in jeder Unterklasse nur für eine einfache Namensänderung nutzlos erscheint.Java klonen abstrakte Objekte

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

Verwendung Reflexion? – johnchen902

Antwort

5

Sie können versuchen, Reflexion zu verwenden:

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

}

im Klon() -Methode aufrufen Sie getClass(). Da der ACloneble abstrakt ist, wird der Aufruf immer zur konkreten Klasse gehen.

public class ClonebaleOne extends AClonable{ 

public ClonebaleOne(){ 
    super(); 
} 

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

}

und

public class ClonebaleTwo extends AClonable{ 

public ClonebaleTwo(){ 
    super(); 
} 

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

}

und schließlich

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()); 

} 

Ausgang:

ClonebaleOne 
    One 
    ClonebaleTwo 
    Two 

Aber es ist mehr ein Hack als eine Lösung

[EDIT] meine zwei Klone schneller waren als;)

[EDIT] auf Vollständigkeit. Eine andere Implementation von clone() kann

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

sein, wenn Ihre abstrakte Klasse Serialazable implementiert. Dort schreiben Sie Ihr Objekt auf Disc und erstellen eine Kopie mit dem Wert von der Disc.

+0

Ich mag Ihre Idee und vielleicht wird es für mich in Zukunft nützlich sein, aber ich denke, ich bin besser dran, nur Klon für jede Unterklasse zu definieren. Schade, es gibt keinen einfacheren Weg, dies zu erreichen. – negoose

+0

Um sie in jeder Unterklasse zu definieren, ist die beste Lösung in der objektorientierten Weise. Ich stimme dort mit Sanbhat überein. Ich fürchte, die Serialazable-Lösung ist die langsamste und es ist auch ein Hack. –

2

Sie können nicht tiefen Klon von abstract Klasse erstellen, weil sie nicht instanziiert werden kann. Alles, was Sie tun können, ist flache Klonen von Object.clone() mit oder this

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

oder

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

Eine abstrakte Klasse kann als Referenz dienen, und es kann keine Instanz haben so seicht Klonen arbeitet bei der Rückkehr dieser Fall

OR

Als besserer Ansatz, können Sie erklären clone() als abstract und Kind Klasse bitten, es zu definieren, so etwas wie dieses

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

Obwohl ich es ist eine gute Idee, zweifeln, könnten Sie Reflexion verwenden:

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

Sie können mit Reflexion beheben:

aber - IMO - ist eine schlechte Implementierung und fehleranfällig mit vielen Gruben; Die beste Verwendung von Cloneable und Object.clone() ist, sie nicht zu benutzen! Sie haben eine Menge Möglichkeiten, dasselbe zu tun (wie Serialisierung für Deep-Clone) und shallow-clone, die Ihnen eine bessere Kontrolle des Flusses ermöglichen.