Java克隆抽象对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18146319/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 22:44:45  来源:igfitidea点击:

Java cloning abstract objects

javaoverridingcloneabstract-classabstract

提问by negoose

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 Shapefrom the toString()of the current one. Obviously I can't do the following because Shapeis abstract. Is there another way to do this because overriding clone in every subclass just for a simple name change seems useless.

我想知道是否有任何方法可以执行以下操作。我有一个抽象类 ,Shape及其所有不同的子类,我想覆盖 clone 方法。我想要在该方法中做的就是ShapetoString()当前的 中创建一个新的。显然我不能做以下事情,因为它Shape是抽象的。是否有另一种方法可以做到这一点,因为仅为了简单的名称更改而在每个子类中覆盖克隆似乎没有用。

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

采纳答案by Jan Piel

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.

在您调用 getClass() 的 clone() 方法中。因为 ACloneble 是抽象的,那里的调用总是会转到具体的类。

   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

[编辑] 完成。clone() 的另一个实现可以是

 @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.

当您的抽象类实现 Serialazable 时。在那里您将对象写入光盘并使用光盘中的值创建副本。

回答by sanbhat

You can't create deep cloneof abstractclass because they can't be instantiated. All you can do is shallow cloningby using Object.clone()or returning this

你不能创建类的深度克隆abstract因为它们不能被实例化。您所能做的就是通过使用或返回进行浅克隆Object.clone()this

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

or

或者

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

An abstract class can act as a reference, and it cannot have an instance so shallow cloning works in this case

一个抽象类可以作为一个引用,它不能有一个实例,所以在这种情况下浅克隆是有效的

OR

或者

As a better approach, you can declare clone()as abstractand ask child class to define it, something like this

作为更好的方法,您可以声明clone()abstract并要求子类定义它,就像这样

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

}

回答by Vincent van der Weele

Although I doubt it is a good idea, you could use reflection:

虽然我怀疑这是一个好主意,但您可以使用反射:

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

回答by Luca Basso Ricci

You can resolve with reflection:

您可以通过反射解决:

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

but - IMO - is a poor implementation and error-prone with a lot of pits; the best use of Cloneableand Object.clone()is to not use them! You have a lot of way to do the same thing (like serialization for deep-clone) and shallow-clone that allow your a better control of flow.

但是 - IMO - 是一个糟糕的实现并且容易出错,有很多坑;最好的使用CloneableObject.clone()不使用它们!你有很多方法可以做同样的事情(比如深度克隆的序列化)和浅克隆,让你更好地控制流程。