对象数组实例的深层副本,Java

时间:2013-02-11 09:47:01

标签: java arrays object deep-copy

我的主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类和我的Ingredient类(配方数组所拥有的对象)都有toString方法和配方调用成分,以便以一种漂亮的小格式打印出来。当我在我的“recipeOne”对象(称为意大利辣香肠披萨)上调用它时,我得到“意大利辣香肠比萨饼:1.0磅面团,8.0盎司酱汁,10.0盎司奶酪”

然后我继续制作对象ressippi并将其设置为recipeOne的克隆,所以这里的所有好处...然后我将ressippi的名称更改为“Pineapple Pizza”并且打印出来的很好,但它不打印3成分recipeOne存储的对象,它应该这样做!

3 个答案:

答案 0 :(得分:3)

将复制构造函数添加到配方类,该配方类创建配方的新实例并复制原始配方中的所有字段。

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

答案 1 :(得分:1)

正如您所知,实现Cloneable实际上并不克隆该对象。你必须明智地实施clone()方法,如果你想要深层复制,那就是你应该实现的。

现在,创建一个具有相同Recipe属性的新Name对象是可以的。之后更改新对象的名称也很合适,它不会更改第一个对象的名称,因为java String是不可变的。

您可能需要查看commons-beanutils包,它为克隆对象提供了方便的代码。

最后,对于“......只传递引用...”,你应该阅读例如。 thisthis主题。

干杯,

答案 2 :(得分:1)

序列化它!看一下deepClone函数,例如:http://www.avajava.com/tutorials/lessons/how-do-i-perform-a-deep-clone-using-serializable.html

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

另外:更改数组的名称,使其与类名不匹配(=令人困惑):

Ingredient Recipe[] = new Ingredient[INGREDIENT_ARRAY_MAX];