对象数组实例的深拷贝,Java

Posted

技术标签:

【中文标题】对象数组实例的深拷贝,Java【英文标题】:Deep Copy of Object Array Instance, Java 【发布时间】:2013-01-26 09:38:23 【问题描述】:

我有一个对象在我的主要Recipe recipeOne = new Recipe("Pepperoni Pizza");

这个对象是这里定义和构造的这个对象数组的一个实例!

public class Recipe implements Cloneable

String Name;

final int INGREDIENT_ARRAY_MAX = 10;

Ingredient Recipe[] = new Ingredient[INGREDIENT_ARRAY_MAX];

public Recipe(String name)

    Name = name;


因此,我希望使用 Recipe ressippi = (Recipe) recipe.clone(); 行制作此对象的深层副本,然后它会将我发送到这里!

public Object clone()

    Recipe cloneRec = new Recipe(Name);

    return cloneRec;


我知道这是一个浅拷贝,因为该方法只传递引用,所以如果我要尝试对作为 recipeOne 克隆的新对象进行名称更改...它会同时更改它们的名称。显然我不想这样,我对此很迷茫,有人可以帮忙吗?

编辑:@Rohit Jain

Recipe 类和成分类(配方数组包含的对象)都具有 toString 方法,并且 recipes 调用成分以便以漂亮的小格式将其全部打印出来。当我在我的“recipeOne”对象(称为意大利辣香肠比萨)上调用它时,我得到“意大利辣香肠比萨:1.0 磅面团、8.0 盎司酱汁、10.0 盎司奶酪”

然后我继续制作 ressippi 对象并将其设置为 recipeOne 的克隆,所以从这里开始一切都很好......然后我将 ressippi 的名称更改为“Pineapple Pizza”,打印效果很好,但它不打印 3 种成分recipeOne 存储的对象,它应该这样做!

【问题讨论】:

看到这个答案:link new String(name) 怎么样? 【参考方案1】:

向配方类添加一个复制构造函数,它会创建一个新的配方实例并复制原始配方中的所有字段。

Recipe.java

public class Recipe implements Cloneable 

    String name;

    final int INGREDIENT_ARRAY_MAX = 10;

    Ingredient[] ingredients = new Ingredient[INGREDIENT_ARRAY_MAX];

    public Recipe(String name) 
        this.name = name;
    

    //Copy Constructor
    private Recipe(Recipe recipe)
        this.name = recipe.name;
        for(int x = 0; x < recipe.ingredients.length; x++)
            this.ingredients[x] = recipe.ingredients[x];
        
    

    public static Recipe newInstance(Recipe recipe)
        return new Recipe(recipe);
    

    //Debug Method
    public static void printRecipe(Recipe recipe)
        System.out.println("Recipe: " + recipe.name);
        for(Ingredient i:recipe.ingredients)
          if(i != null && i.getName() != null)
              System.out.println("Ingredient: " + i.getName());           
          
        
    

    //Test Method
    public static void main(String[] args) 
        Recipe recipe = new Recipe("Chicken Soup");
        recipe.ingredients[0] = new Ingredient("Chicken");
        recipe.ingredients[1] = new Ingredient("Broth");

        Recipe copy = new Recipe(recipe);
        copy.ingredients[2] = new Ingredient("Rice");
        copy.name = "Chicken Rice Soup";

        printRecipe(recipe);
        printRecipe(copy);
        System.out.println(recipe == copy);
        System.out.println(recipe.ingredients == copy.ingredients);
    

Ingredient.java

public class Ingredient 

    private String name;

    public Ingredient(String name)
        this.name = name;
    

    public String getName() 
        return name;
    


    public void setName(String name) 
        this.name = name;
    

【讨论】:

答案已经很老了,但我认为“this.ingredients[x] = recipe.ingredients[x];”不应该在深拷贝中完成。您需要再次对每个元素进行深层复制。【参考方案2】:

序列化!看看这里的 deepClone 函数示例:http://www.avajava.com/tutorials/lessons/how-do-i-perform-a-deep-clone-using-serializable.html

其他关于字符串不可变的回答当然是正确的,但你试图用字符串示例描述的问题只是一个坏例子;像成分数组这样更复杂的对象仍然是通过引用复制的。

另外:更改数组的名称,使其与类名不匹配(=混淆):

Ingredient Recipe[] = new Ingredient[INGREDIENT_ARRAY_MAX];

【讨论】:

【参考方案3】:

正如您所发现的,实现Cloneable 实际上并没有克隆对象。你必须明智地实现clone() 方法,如果你想要一个深拷贝,那就是你应该实现的。

现在,创建一个具有相同Name 属性的新Recipe 对象是完全可以的。并且之后修改新对象的名字也是可以的,不会改变第一个对象的名字,因为javaString是不可变的。

您可能想看看commons-beanutils 包,它提供了用于克隆对象的便捷代码。

最后,至于“...仅传递引用...”,您应该阅读例如。 this 和 this 线程。

干杯,

【讨论】:

以上是关于对象数组实例的深拷贝,Java的主要内容,如果未能解决你的问题,请参考以下文章

javascript 数组以及对象的深拷贝(复制数组或复制对象)的方法

对象数组的深拷贝

对象或数组 或数组对象的深拷贝

拷贝数组和对象,深拷贝,浅拷贝

6javascript中对象和数组的深拷贝

javascript 数组以及对象的深拷贝(复制数组或复制对象)的方法