Skip to main content

Section 11.21 Worked Example: Shallow and Deep Copies

Subgoals for Evaluating Arrays.

  1. Declaring and initialization of array
    1. Set up a one dimensional table (i.e., one row) with 0 to (size - 1) elements
    2. Upon instantiation of an array object, all elements contain default value for datatype stored in array OR values from the initializer list
  2. Determine access or change of element, or action on entire array object, and update slots as needed (remembering assignment subgoals)
  3. Accessing array element
    1. Evaluate expression within [ ] which will be the index for element to be accessed
    2. arrayName[index] returns value stored at that index
    3. index must be between 0 and arrayName.length - 1, inclusive otherwise IndexOutOfBounds exception occurs
  4. Changing value of an array element
    1. Evaluate expression within [ ] which will be the index for element to be accessed
    2. arrayName[index] will now contain the value on the RHS of assignment statement
    3. (remember the assignment subgoals for verifying data types and evaluating expressions)
    4. (remember rules for index values)
  5. Whole array actions
    1. Pass as argument - a copy of the reference to the instantiated array is passed to the method. This means that any changes made to the array elements inside the method are persistent. The one exception to this is if you assign the argument to reference a different array in memory.
    2. Assignment - changes the reference to point to the array on the RHS of the assignment operator.

Subsection 11.21.1

Problem: Evaluate the following code - what is the output?
        public static void main(String[] args) {
   Person [] people = new Person[3];
   Person maria = new Person("Maria Santos", 156);
   people[0] = maria;
   people[1] = new Person("Caiji Zheng", 742);
   people[2] = new Person("Mary Smith", 548);


   Person[] morePeople = new Person[people.length];
   morePeople = people;
   morePeople[1].setName("Mickey Mouse");
   System.out.println("people contains " + printObjArr(people));
   System.out.println("morePeople contains " + printObjArr(morePeople));


   /**********************************************************************/


   morePeople = new Person[people.length];
   for (int x = 0; x < people.length; x++)
       morePeople[x] = people[x];


   morePeople[1].setName("Donald Duck");
   System.out.println("people contains " + printObjArr(people));
   System.out.println("morePeople contains " + printObjArr(morePeople));


   /**********************************************************************/


   morePeople = new Person[people.length];
   for (int x = 0; x < people.length; x++)
       morePeople[x] = new Person(people[x].getName(), people[x].getId());


   morePeople[1].setName("Goofy");
   System.out.println("people contains " + printObjArr(people));
   System.out.println("morePeople contains " + printObjArr(morePeople));
}


public static String printObjArr(Object[] arr) {
   String result = "";
   for (Object o : arr) {
       result += o;
       result += "  ";
   }
   return result;
}
This code also makes use of a Person class, which is defined here:
public class Person {
    private String name;    // name of person
    private int id;         // person's id

    // overloaded constructor
    public Person(String name, int id) {
        setName(name);
        setId(id);
    } 
             
    // default constructor
    public Person() {
    }

    // Accessors and Mutators
    public String getName() {
        return name;
    } 
             
    public void setName(String name) {
        if (name.length() != 0)     // name must not be null
            this.name = name;
    } 
             
    public int getId() {
        return id;
    } 
             
    public void setId(int id) {
        this.id = id;
    } 
             
    // toString to allow conversion to String
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", id=" + id + '}';
    }
}

Subsection 11.21.2 SG1: Declaring and initialization of array

The first 6 lines of the main() method are declaring and initializing an array of Person object references:
Person [] people = new Person[3];
Person maria = new Person("Maria Santos", 156);
people[0] = maria;
people[1] = new Person("Caiji Zheng", 742);
people[2] = new Person("Mary Smith", 548);
Person[] morePeople = new Person[people.length];
Here is a memory representation:
Figure 11.21.1.
Notice that at this point the array morePeople just contains values of null, but has the same number of elements as the array people. Also notice that you can access the Person object representing Miara Santos through the variable maria or people[0]. When you have two variables that access the same object, we say the variables alias one another.

Subsection 11.21.3 SG2: Determine access or action, SG5: Whole array actions, array assignment

The next line of code assigns the variable people to the variable morePeople:
morePeople = people;
They are now aliases of each other - the variables people and morePeople point to the same array! Here is the memory representation:
Figure 11.21.2.
So these next statements:
morePeople[1].setName("Mickey Mouse");
System.out.println("people contains " + printObjArr(people));
System.out.println("morePeople contains " + printObjArr(morePeople));
Changes the value for the reference at morePeople[1] (which also changes people[1]!):
Figure 11.21.3.
Will generate this output:
people contains Person{name=’Maria Santos’, id=156} Person{name=’Mickey Mouse’, id=742} Person{name=’Mary Smith’, id=548}
morePeople contains Person{name=’Maria Santos’, id=156} Person{name=’Mickey Mouse’, id=742} Person{name=’Mary Smith’, id=548}

Subsection 11.21.4 SG2: Determine access or action

Let’s look at the next section of code:
morePeople = new Person[people.length];
for (int x = 0; x < people.length; x++)
   morePeople[x] = people[x];
Here we have allocated new memory for the morePeople array (so memory looks like figure 11.22.1 except that the name for the instance in element index 1 is still "Mickey Mouse").
The for loop assigns the reference in each element of people to the corresponding element in morePeople. So now memory looks like:
Figure 11.21.4.
This is known as a shallow copy - copying only the references. This makes each element of the people array an alias to the corresponding element in the morePeople array.
The next lines of code:
morePeople[1].setName("Donald Duck");
System.out.println("people contains " + printObjArr(people));
System.out.println("morePeople contains " + printObjArr(morePeople));
will result in the name value in the morePeople[1] reference changing:
Figure 11.21.5.
Thus the output generated is:
people contains Person{name=’Maria Santos’, id=156} Person{name=’Donald Duck’, id=742} Person{name=’Mary Smith’, id=548}
morePeople contains Person{name=’Maria Santos’, id=156} Person{name=’Donald Duck’, id=742} Person{name=’Mary Smith’, id=548}

Subsection 11.21.5 SG2: Determine access or action

Let’s look at the last section of code:
morePeople = new Person[people.length];
for (int x = 0; x < people.length; x++)
   morePeople[x] = new Person(people[x].getName(), people[x].getId());
Here we have allocated new memory for the morePeople array (so memory looks like figure 11.22.1 except that the name for the instance in element index 1 is still "Donald Duck" ).
The for loop assigns the reference in each element of people to a new Person instance with the values from the corresponding element in morePeople. So now memory looks like:
Figure 11.21.6.
This is known as a deep copy - making new instances with identical values. Now there are no aliases and the objects are independent.
The next lines of code:
morePeople[1].setName("Goofy");
System.out.println("people contains " + printObjArr(people));
System.out.println("morePeople contains " + printObjArr(morePeople));
Will only change the morePeople[1] name value. Memory looks like:
Figure 11.21.7.
And the output generated is:
people contains Person{name=’Maria Santos’, id=156} Person{name=’Donald Duck’, id=742} Person{name=’Mary Smith’, id=548}
morePeople contains Person{name=’Maria Santos’, id=156} Person{name=’Goofy’, id=742} Person{name=’Mary Smith’, id=548}

Subsection 11.21.6

What is the output produced by the code?
Answer.
people contains Person{name=’Maria Santos’, id=156} Person{name=’Mickey Mouse’, id=742} Person{name=’Mary Smith’, id=548}
morePeople contains Person{name=’Maria Santos’, id=156} Person{name=’Mickey Mouse’, id=742} Person{name=’Mary Smith’, id=548}
people contains Person{name=’Maria Santos’, id=156} Person{name=’Donald Duck’, id=742} Person{name=’Mary Smith’, id=548}
morePeople contains Person{name=’Maria Santos’, id=156} Person{name=’Donald Duck’, id=742} Person{name=’Mary Smith’, id=548}
people contains Person{name=’Maria Santos’, id=156} Person{name=’Donald Duck’, id=742} Person{name=’Mary Smith’, id=548}
morePeople contains Person{name=’Maria Santos’, id=156} Person{name=’Goofy’, id=742} Person{name=’Mary Smith’, id=548}
You have attempted of activities on this page.