Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deep Copy of Object Array Instance, Java

I have an object made in my main Recipe recipeOne = new Recipe("Pepperoni Pizza");

This object is an instance of this Object Array defined and constructed here!

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;

}

So I am looking to make a deep copy of this object with the line Recipe ressippi = (Recipe) recipe.clone(); and it sends me here!

public Object clone(){

    Recipe cloneRec = new Recipe(Name);

    return cloneRec;

}

I know this is currently a shallow copy because the method only passes references, so if I was to attempt a name change on my new Object that was a clone of recipeOne...it would change both of their names. Obviously I do not want that, I'm fairly lost on this, can anyone help?

EDIT:@Rohit Jain

Both my Recipe class as well as my Ingredient class (the objects the recipe array holds) have toString methods and recipes calls on ingredients in order to print it all out in a nice little format. When I call it on my "recipeOne" object (the one called pepperoni pizza) i get "Pepperoni Pizza: 1.0 Pounds of Dough, 8.0 Ounces of Sauce, 10.0 Ounces of Cheese"

Then I proceed to make the object ressippi and set that to the clone of recipeOne, so all good from here...then I change ressippi's name to "Pineapple Pizza" and that prints out fine but it doesnt print the 3 ingredient objects that recipeOne stored, which it is suppose to do!

like image 910
Sherifftwinkie Avatar asked Feb 11 '13 09:02

Sherifftwinkie


People also ask

What is a deep copy of an array Java?

So any changes to the copied array will reflect in the original. Java cloning is an example of a shallow copy. A deep copy is the one wherein we need a complete copy of the object so that when we clone or copy that object, it is an independent copy.

Is arrays copy of a deep copy?

It just copies the source element values into the target elements. Again we have the same effect as a deep copy at the expense of an operation needing much less code than for a deep copy. So Arrays. copyOf(..) is a 'cheap' deep copy for both primitive and 1-D Object arrays.


2 Answers

Add a copy constructor to the recipe class, which creates a new instance of recipe and copies all of the fields from an original recipe.

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;
    }
}
like image 60
Kevin Bowersox Avatar answered Sep 23 '22 15:09

Kevin Bowersox


As you have found out, implementing the Cloneable doesn't actually clone the object. You'll have to implement the clone() method sensibly, and if you want a deep copy, that's what you should implement.

Now, creating a new Recipe object with the same Name attribute is quite OK. And changing the name for the new object afterwards is also quite okay, it won't change the name of the first object as java String's are immutable.

You may want to have a look at the commons-beanutils package, which provides handy code for cloning objects.

Finally, as for "...only passes references..." you should read eg. this and this thread.

Cheers,

like image 45
Anders R. Bystrup Avatar answered Sep 22 '22 15:09

Anders R. Bystrup