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 メソッドが必要であり、すべてを素敵な小さな形式で出力するために、材料に対するレシピ呼び出しが必要です。「recipeOne」オブジェクト (ペパロニ ピザと呼ばれるもの) でそれを呼び出すと、「ペパロニ ピザ: 1.0 ポンドの生地、8.0 オンスのソース、10.0 オンスのチーズ」が得られます。

次に、オブジェクト ressippi の作成に進み、ressippi のクローンに設定します。ここからはすべて問題ありません...次に、ressippi の名前を「パイナップル ピザ」に変更すると、正常に出力されますが、recipeOne の 3 つの材料オブジェクトは出力されません。保存されているはずです。

4

3 に答える 3

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

成分.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

シリーズ化!ここで例として、deepClone 関数を見てみましょう: http://www.avajava.com/tutorials/lessons/how-do-i-perform-a-deep-clone-using-serializable.html

もちろん、文字列が不変であるという他の回答は真実ですが、文字列の例で説明しようとした問題は単なる悪い例です。Ingredients 配列のような複雑なオブジェクトは、依然として参照によってコピーされます。

また、クラス名と一致しないように配列の名前を変更します(=紛らわしい):

Ingredient Recipe[] = new Ingredient[INGREDIENT_ARRAY_MAX];
于 2013-02-11T09:55:04.763 に答える
1

お気づきのように、 を実装しCloneableても実際にはオブジェクトが複製されません。メソッドを賢明に実装する必要がありclone()ます。ディープ コピーが必要な場合は、それを実装する必要があります。

これで、同じ属性を持つ新しいRecipeオブジェクトを作成してNameもまったく問題ありません。また、後で新しいオブジェクトの名前を変更しても問題ありませんString。Java は不変であるため、最初のオブジェクトの名前は変更されません。

オブジェクトを複製するための便利なコードを提供するcommons-beanutilsパッケージを確認することをお勧めします。

最後に、「...参照のみを渡す...」については、たとえばを読む必要があります。これこのスレッド。

乾杯、

于 2013-02-11T09:52:05.313 に答える