Welcome to Lesson 9!


Learning Objectives for Today's Lesson

By the end of today's lesson, you should know...
  • What is this object?
  • What is the purpose of a copy constructor?
  • What is the signature of a copy constructor?
  • What is the difference between a deep copy and a shallow copy?


1. Using this

  • Each object maintains its own set of instance variables
  • This permits each object to have its own state based on the values stored
  • For example, consider a class Date with 3 instance variables
    public class Date {
        private int month;
        private int day;
        private int year;
    
        // member methods not shown
    }
    
  • A distinct area of memory is set aside each time an object of this class is created
  • For example, if we create two objects referenced by variables named a and b:
    Date a = new Date(1, 1, 1970);
    Date b = new Date(12, 25, 2002);
    
  • Memory is set aside for both objects:
separate memory is set aside for both objects

  • According to the Oracle documentation on this: within an instance method or a constructor, this is a reference to the current object — the object whose method or constructor is being called, or whose member variables are currently being accessed or mutated.
  • You can refer to any member variable of the current object from within an instance method or a constructor by using this.
  • It is used with the dot '.' operator like any other object reference:
    this.month
  • You can understand this to be the current object on which a method is being called.
  • For example:
public class Date {
    private int month;
    private int day;
    private int year;

    public int getDay() {
        return day; //return the value of the current object's day variable
    }
    //other member methods not shown }
  • The above getDay() method could be rewritten as follows:
public class Date {
    private int month;
    private int day;
    private int year;

    public int getDay() {
        return this.day; //return the value of the current object's day variable
    }
    //other member methods not shown }
  • To further understand this concept, note that an Object does not receive a name until the constructor is called.
public static void main(String[] args) {
    Date d = new Date(); //name of Object is now d
}
  • The keyword this stands in place of the name of an object inside of a class definition, as this Object will not be assigned a name until later in the program (as shown in the main method above).
  • Use of the this reference is optional unless needed to clarify variable scope or avoid the problem of "Shadowing" we discussed last class.
  • For instance, we could define a constructor of Date:
    public Date(int month, int day, int year) {
        this.month = month;
        this.day = day;
        this.year = year;
    }
    
  • We now need this to differentiate between member variables and local variables
  • Assume the we add a method with the following signature to the Date class:
public boolean sameDate(Date anotherDate) {

  • The purpose of this method is to compare the current Date object to another Date object passed as a parameter.
  • We know that both Date objects store their own copies of the month, day, and year variables.
  • Since I am now comparing two Date objects within a single method, I need to specify which Date's month, day, and year variables when I use them:
  • e.g.
this.month == anotherDate.month
  • Therefore, we might write this method as follows:
public boolean sameDate(Date anotherDate) {
if (this.month == anotherDate.month &&
this.day == anotherDate.day &&
this.year == anotherDate.year) {

return true;
} else {
return false;
}
}
  • Note that this is a final variable (constant)
  • Thus, you cannot assign a new Object value to this
this = null; //will not compile


Group Activity:

  • There is a problem with the below mutator methods. Solve the problem using the keyword this.
public class Address {
    private int number;
    private String street;

    //write your two constructors here!

    public int getNumber() {
        return number;
    }

    public String getStreet() {
        return street;
    }

    public void setNumber(int number) {
        number = number;
    }
   
    public void setStreet(String street) {
        street = street;
    }

    @Override public String toString() {
        return number + " " + street;
    }

}

2. Copy Constructors

  • When writing a copy constructor, the meaning of this becomes clear.
Copy constructor: a constructor with a single parameter of the same type as the class that makes an exact but independent copy of the object parameter.
  • A copy constructor is a constructor with a single parameter of the same type as the class
  • The purpose of a copy constructor is to create an exact copy of the parameter that is a separate and independent object
  • The following example is the part of the Person class containing a copy constructor

Example Class with a Copy Constructor

public class Person {
    private String name;
    private int age;
    private boolean isSingle; 

    // copy constructor
    public Person(Person original) {
        if(original != null) {
            this.name = original.name;     this.age = original.age;
            this.isSingle = original.isSingle;
        }
        
     } // other members not shown }

public class PersonTest {
    public static void main(String[] args) {
        Person p1 = new Person("Bao", 23, true);
        Person p2 = new Person(p1); //calling the copy constructor
    }
}

Comments About the Copy Constructor

  • Note we were not required to use the keyword this as shown above, however, it helped us to differentiate between the two objects - the one passed in as a parameter (original) that we were trying to make a copy of and the empty one (this)
  • The copy constructor copies from the member variables of the original object
  • When writing a copy constructor it is important keep in mind that you do not want to rename the same variable with a new name.
  • The below is an example of a copy constructor that makes a shallow copy:

public class Person {
private String name;
private Date birthday;

public Person(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}

// copy constructor
public Person(Person original) {
if(original != null) {
this.name = original.name;
this.birthday = original.birthday;
}
}

public String getName() {
return name;
}

public Date getBirthday() {
return birthday;
}

public void setName(String name) {
this.name = name;
}

public void setBirthday(Date birthday) {
this.birthday = birthday;
}

@Override public String toString() {
return "Name: " + name + "\n"
+ "Birthday: " + birthday + "\n";
}

}

class Date {
private int month;
private int day;
private int year;

public Date(int m, int d, int y) {
month = m;
day = d;
year = y;
}

public int getDay() {
return day;
}

public int getMonth() {
return month;
}

public int getYear() {
return year;
}

public void setDay(int day) {
this.day = day;
}

public void setMonth(int month) {
this.month = month;
}

public void setYear(int year) {
this.year = year;
}

@Override public String toString() {
return month + "/" + day + "/" + year;
}

}

public class PersonTest {

public static void main(String[] args) {
Date d = new Date(10, 13, 95);
Person p1 = new Person("Bao", d);
Person p2 = new Person(p1); //calling the "shallow" copy constructor

System.out.println("After calling copy constructor:\n");
System.out.println(p1);
System.out.println(p2);

//updating p2's name and birth month
p2.setName("Ben");
p2.getBirthday().setMonth(1);

System.out.println("After updating p2's name and birth month:\n");
System.out.println(p1);
System.out.println(p2);

//Why do they have the same birthday after update?

}
}

  • The above shallow copy is considered bad programming practice in most cases.
    • It simply sets two reference variables to have the same memory address.
  • The shallow copy can cause confusion when the user of the class expects that the birthday variables for p1 and p2 are two different objects.
    • However, changes made to p1's birthday will also affect p2's birthday
  • Instead, it is important to make a deep copy - where new memory is allocated for the birthday field.
    public Person(Person original) {
        if (original != null){
            this.name = original.name;

            this.birthday = new Date(original.birthday.getMonth(),
                original.birthday.getDay(), original.birthday.getYear());

        }
     }
  • With a deep copy, you make a separate and distinct copy of the original object, that stores the same data as the original object (at different locations in memory).
  • Below is a revised version of the same program - this time with a deep copy constructor

public class Person {
    private String name;
    private Date birthday;

    public Person(String name, Date birthday) {
        this.name = name;
        this.birthday = birthday;
    }
   
    // copy constructor
    public Person(Person original) {
        if(original != null) {
            this.name = original.name;
            this.birthday = new Date(
                    original.birthday.getMonth(),
                    original.birthday.getDay(),
                    original.birthday.getYear());
        }
     }

    public String getName() {
        return name;
    }
   
    public Date getBirthday() {
        return birthday;
    }
   
    public void setName(String name) {
        this.name = name;
    }
   
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
   
    @Override public String toString() {
        return "Name: " + name + "\n"
                + "Birthday: " + birthday + "\n";
    }

}

class Date {
    private int month;
    private int day;
    private int year;

    public Date(int m, int d, int y) {
        month = m;
        day = d;
        year = y;
    }
   
    public int getDay() {
        return day;
    }

    public int getMonth() {
        return month;
    }
 
    public int getYear() {
        return year;
    }
   
    public void setDay(int day) {
        this.day = day;
    }
   
    public void setMonth(int month) {
        this.month = month;
    }
   
    public void setYear(int year) {
        this.year = year;
    }
   
    @Override public String toString() {
        return month + "/" + day + "/" + year;
    }

}


public class PersonTest {
   
    public static void main(String[] args) {
        Date d = new Date(10, 13, 95);
        Person p1 = new Person("Bao", d);
        Person p2 = new Person(p1); //calling the "deep" copy constructor
       
        System.out.println("After calling copy constructor:\n");
        System.out.println(p1);
        System.out.println(p2);
       
        //updating p2's name and birth month
        p2.setName("Ben");
        p2.getBirthday().setMonth(1);
        
        System.out.println("After updating p2's name and birth month:\n");
        System.out.println(p1);
        System.out.println(p2);
       
        //Why do they have different birthdays after update?
       
    }
}


Activity 9.1: A Person Class with a Copy Constructor (10 pts)

  • Open up the Person.java class from the last activity
  • Let's update it to contain a copy constructor, as follows:
    • It takes in a Person object as a parameter
    • It assigns this to have the same age, name and gender as the parameter
    • It assigns address a deep copy of the address field. In other words, you will need to call the Address constructor to achieve the deep copy.
    • See example above of a deep copy in the Copy Constructor portion of the lesson notes.
  • Copy and paste the new test file below into PersonTest.java (you can erase the old contents of the file), and update the incomplete line.
/**
* PersonTest.java, Activity 9.1
* @author
* CIS 36B
*/

import java.util.Scanner;

public class PersonTest {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String name, gender, street;
        int age, number;
        Person person1;
     
        System.out.print("Welcome!\n\nEnter your name: ");
        name = input.nextLine();
       
        System.out.print("Enter your age: ");
        age = input.nextInt();
       
        System.out.print("Enter your gender: ");
        gender = input.next();
        
        System.out.print("Enter the street number of your address: ");
        number = input.nextInt();
       
        System.out.print("Enter the name of your street: ");
        input.nextLine();
        street = input.nextLine();
        
        Address address = new Address(number, street);
       
        person1 = new Person(name, age, gender, address);
    
        Person person2 = //fill in line to call copy constructor here
       
        System.out.print("\nEnter the name of another person with your age and gender: ");
        name = input.nextLine();
       
        System.out.print("Enter " + name + "'s street number: ");
        number = input.nextInt();
       
        System.out.print(
"Enter " + name + "'s street name: ");
        input.nextLine();
        street = input.nextLine();

        person2.setName(name);
        person2.getAddress().setNumber(number);
        person2.getAddress().setStreet(street);

           System.out.println("\nYour Summary:\n" + person1);       
        System.out.println("\nAnother student with your "
            + "same age and gender: \n" + person2);
        input.close();
   
    }
}
  • When you get the correct output (as shown below), upload Address.java, Person.java and PersonTest.java to Canvas

Sample Output (Note that user input may vary):

Welcome!

Enter your name: Wen Li
Enter your age: 23
Enter your gender: Male
Enter the street number of your address: 2141
Enter the name of your street: W. Elm Ave

Enter the name of another person with your age and gender: C.J. Nguyen
Enter C.J. Nguyen's street number: 4567
Enter C.J. Nguyen's street name: S. 7th St


Your Summary:
Name: Wen Li
Age: 23
Gender: Male
Address: 2141 W. Elm Ave


Another student with your same age and gender:
Name: C.J. Nguyen
Age: 23
Gender: Male
Address: 4567 S. 7th St


Wrap Up: 
  • Answer the practice exam questions from this lesson on Canvas.


Upcoming Assignments:

  • Activities 9.1 due Tuesday at 11:59pm on Canvas
  • Lesson 9 Practice Exam Questions due Tuesday at 11:59pm on Canvas
  • Peer Reviews of Lesson 9 Practice Exam Questions due Saturday at 11:59pm
  • Lab 5 due next Monday at 11:59pm

~ Have a Great Day! ~