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