Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java cloning abstract objects

I'm wondering if there is any way to do the following. I have an abstract class, Shape, and all its different subclasses and I want to override the clone method. All I want to do in the method is create a new Shape from the toString() of the current one. Obviously I can't do the following because Shape is abstract. Is there another way to do this because overriding clone in every subclass just for a simple name change seems useless.

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()
    }
}
like image 382
negoose Avatar asked Aug 09 '13 12:08

negoose


People also ask

Can we clone an abstract class?

The abstract base class specifies an abstract Clone() method which must be implemented by all derived classes. Every class except the abstract base class must have a protected copy constructor.

Can we clone object in Java?

Object cloning refers to the creation of an exact copy of an object. It creates a new instance of the class of the current object and initializes all its fields with exactly the contents of the corresponding fields of this object. In Java, there is no operator to create a copy of an object.

Can abstract objects be instantiated?

Abstract classes cannot be instantiated, but they can be subclassed. When an abstract class is subclassed, the subclass usually provides implementations for all of the abstract methods in its parent class.

What are the types of object cloning in Java?

There are two types of object cloning - shallow cloning, and deep cloning.


1 Answers

You can try to use reflection:

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

}

in the clone() method you call getClass(). Because the ACloneble ist abstract, there call will allways go to the concrete class.

   public class ClonebaleOne extends AClonable{

public ClonebaleOne(){
    super();
}

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

}

and

  public class ClonebaleTwo extends AClonable{

public ClonebaleTwo(){
    super();
}

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

}

and finally

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

}

Output:

  ClonebaleOne
  One
  ClonebaleTwo
  Two

But it's more a hack than a solution

[EDIT] my two clones were faster than ;)

[EDIT] To be complete. Another implentation of clone() can be

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

when your abstract class implements Serialazable. There you write your object to disc and create a copy with the value from the disc.

like image 60
Jan Piel Avatar answered Oct 10 '22 07:10

Jan Piel