深度复制对象数组

时间:2014-09-09 19:20:08

标签: java arrays clone

我还不熟悉Java,现在我正在尝试复制Menu。我想我已经做了一点,我在其中创建了一个新的MenuItems的新Menu菜单。 MenuItems是另一个具有两个字符串变量和一个double变量的类,即itemName和itemDescription以及itemPrice。所以我试图将内容,原始MenuItems的三个变量复制到MenuItems副本中,但我不知道如何。我一直试图将克隆副本的名称设置为原始名称。

public class Menu 
{
    Menu()
    {

    }

    final int maxItems = 50;

    MenuItem[] food = new MenuItem[maxItems + 1];


    public Object clone()
    {
        Menu menuClone = new Menu();
        MenuItem[] foodClone = new MenuItem[maxItems + 1];

        for(int i = 1; i <= maxItems + 1; i++)
        {  
            foodClone[i] = new MenuItem();
            foodClone[i] = food[i].setItemName();
        }

    }

这是MenuItem类:

public class MenuItem 
{
    private String name;
    private String descrip;
    private double price;


    MenuItem()
    {

    }


    public String getItemName()
    {
        return name;
    }

    public String getItemDescrip()
    {
        return descrip;
    }

    public double getPrice()
    {
        return price;
    }

    public void setItemName(String itemName)
    {
        name = itemName; 
    }

    public void setItemDescrip(String itemDescrip)
    {
        descrip = itemDescrip;
    }

    public void setPrice(double itemPrice) throws IllegalArgumentException
    {
        if(itemPrice >= 0.0)
            price = itemPrice;
        else
            throw new IllegalArgumentException("Enter only positive values");
    }

    public String toString(){
        return "Name: " + name + ", Desc: " + descrip;
    }
}

2 个答案:

答案 0 :(得分:1)

你几乎就在那里,你有:

foodClone[i] = food[i].setItemName();

你可能想要(除了MenuItem的其他变量)

foodClone[i].setItemName(food[i].getItemName())`

但是,最好使用克隆方法或复制构造函数(好吧,copy constructor arguably might be best)。

我更喜欢使用复制构造函数,例如:

MenuItem(MenuItem menuItemToClone)
{
     this.name = menuItemToClone.name;
     this.descrip = menuItemToClone.descrip;
     this.price = menuItemToClone.price;
}

然后你会这样做:

foodClone[i] = new MenuItem(food[i]);

答案 1 :(得分:0)

克隆仅提供浅层副本,尽管有一些先前的建议。

深度复制问题的常见解决方案是使用Java对象序列化(JOS)。这个想法很简单:使用JOS的ObjectOutputStream将对象写入数组,然后使用ObjectInputStream重新构建对象的副本。结果将是一个完全不同的对象,具有完全不同的引用对象。 JOS负责所有细节:超类字段,跟随对象图,以及处理对图中同一对象的重复引用。图3显示了使用JOS进行深层复制的实用程序类的初稿。

import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;

/**
 * Utility for making deep copies (vs. clone()'s shallow copies) of 
 * objects. Objects are first serialized and then deserialized. Error
 * checking is fairly minimal in this implementation. If an object is
 * encountered that cannot be serialized (or that references an object
 * that cannot be serialized) an error is printed to System.err and
 * null is returned. Depending on your specific application, it might
 * make more sense to have copy(...) re-throw the exception.
 *
 * A later version of this class includes some minor optimizations.
 */
public class UnoptimizedDeepCopy {

/**
 * Returns a copy of the object, or null if the object cannot
 * be serialized.
 */
public static Object copy(Object orig) {
    Object obj = null;
    try {
        // Write the object out to a byte array
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(bos);
        out.writeObject(orig);
        out.flush();
        out.close();

        // Make an input stream from the byte array and read
        // a copy of the object back in.
        ObjectInputStream in = new ObjectInputStream(
            new ByteArrayInputStream(bos.toByteArray()));
        obj = in.readObject();
    }
    catch(IOException e) {
        e.printStackTrace();
    }
    catch(ClassNotFoundException cnfe) {
        cnfe.printStackTrace();
    }
    return obj;
}

}

不幸的是,这种方法存在一些问题:

  1. 只有当被复制的对象以及对象直接或间接引用的所有其他对象都是可序列化的时,它才会起作用。 (换句话说,它们必须实现java.io.Serializable。)幸运的是,通常只需声明给定的类实现java.io.Serializable并让Java的默认序列化机制完成它们就足够了。

  2. Java对象序列化很慢,使用它进行深层复制需要序列化和反序列化。有一些方法可以加快速度(例如,通过预先计算串行版本ID并定义自定义的readObject()和writeObject()方法),但这通常是主要的瓶颈。

  3. java.io包中包含的字节数组流实现设计得足够通用,可以很好地为不同大小的数据执行,并且可以安全地在多线程环境中使用。但是,这些特性会减慢ByteArrayOutputStream和(在较小程度上)ByteArrayInputStream。

  4. 来源:http://javatechniques.com/blog/faster-deep-copies-of-java-objects/