5

我有一个主要的对象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 方法,并且 recipes 调用了成分,以便以漂亮的小格式将其全部打印出来。当我在我的“recipeOne”对象(称为意大利辣香肠比萨)上调用它时,我得到“意大利辣香肠比萨:1.0 磅面团、8.0 盎司酱汁、10.0 盎司奶酪”

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

4

3 回答 3

3

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

食谱.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);
    }
}

成分.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;
    }
}
于 2013-02-11T10:17:39.430 回答
1

正如您所发现的,实现Cloneable并不会真正克隆对象。您必须clone()明智地实现该方法,如果您想要一个深层副本,那就是您应该实现的。

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

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

最后,至于“...仅通过引用...”您应该阅读例如。这个这个线程。

干杯,

于 2013-02-11T09:52:05.313 回答
1

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

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

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

Ingredient Recipe[] = new Ingredient[INGREDIENT_ARRAY_MAX];
于 2013-02-11T09:55:04.763 回答