Creating Objects and Object Variables
Assigning one object variable to another copies the reference stored in the first variable, not the object it refers to.
Why Copying an Object Variable Surprises Learners
Many learners arrive at object-oriented programming with a habit picked up from working with plain numbers. When you write y = x for an int, you end up with two independent values. Change y later and x is untouched. It is natural to assume the same rule applies when variables hold objects, and that assigning one object variable to another produces a second, separate copy of the object. That assumption is the misconception this article addresses. It is worth examining carefully because the code runs without any error even when the assumption is wrong.
What do you think happens?
Suppose std2 is assigned so that it refers to the same object that std1 already refers to. You then change a field through std2. What do you expect std1 to show when you read that same field: the original value, or the new value?
Reveal answer
The new value, because both variables refer to the same object
An assignment between object variables copies the reference stored in the first variable, not the object it refers to. Both variables therefore lead to one object, so a field changed through either variable is visible through the other.
What an Object Variable Holds
Many beginners picture a variable as a labeled box that holds an object. When they write a line that creates a Student, they imagine the Student sitting inside a box named std. This picture feels natural, and it is the first thing this article asks you to set aside. The picture fails in exactly the places where programs behave in surprising ways, so it is worth replacing it before relying on any other model.
Now try a prediction before reading the explanation. Suppose a variable std has been declared with the class type Student, and the program runs the single statement std = new Student(); Ask yourself what the variable std holds once that line has finished. Does it hold the Student object itself, or something that leads to the object? Choose an answer now, even if you are unsure. Then compare it with the explanation below and notice where your mental picture differs.
The value of a variable like std is a reference, also called a pointer, to the object. The object itself lives in the heap. The variable and the object are two separate things joined by a link. The variable is not a container that the object sits inside. The correct way to describe the relationship is that the variable std refers to, or points to, the object, not that the object is stored in the variable.
Read the diagram with the arrow as the important part. The arrow shows that std refers to the object. The object is not drawn inside the variable box, because the variable does not contain it. If you find yourself saying that the object is stored in std, replace that sentence with one saying that std refers to the object.
How the new Operator Creates an Object
The new operator is the mechanism that brings an object into existence in a program. When you write new followed by a class name and parentheses, the operator does two things. It creates an object that is an instance of that class, and it returns a reference to that object. The returned reference is what gets stored in the variable. The created object is a separate thing from the reference that points to it.
The operator also does more work behind the scenes. It calls a special subroutine defined in the class, called a constructor. The constructor is the part of the class responsible for setting up a new instance. You do not call the constructor as a separate step; the new operator invokes it as part of creating the object.
- 1The new operator is evaluated for the expression new
Student(...) - 2The constructor defined in the Student class runs and sets up the new instance
- 3The new object is finished, and the operator produces a reference to it
- 4The assignment stores that reference in the variable on the left side, so the variable is the last participant in the chain and receives a reference, not the object
Tracing Shared References Through a Student Example
The consequence of shared references is that a field can be reached through two different variable names. Writing to the field through one name changes what the other name reads. The following example uses a Student class with a name field. The class is generated for illustration, but the behavior it demonstrates is the one described in the source material.
- The class defines one instance variable, name, which holds a String
- The constructor sets up the new instance when new
Student(...)runs - The
setNamemethod changes the name field of the object the call is made on
Cara
true
false- Lines 1 and 2 create two separate Student objects, each with its own reference
- Line 3 copies the reference in std1 into std3, so std1 and std3 now refer to the same object
- Line 4 changes the name field through std3
- Line 5 reads the same field through std1 and sees the change
- Line 6 is true because std1 and std3 refer to the same object
- Line 7 is false because std1 and std2 refer to different objects
Notice what the assignment std3 = std1 did not do. It did not create a new Student, and it did not copy the name field. It moved a reference from one variable into another and nothing more. The line looks like it is performing a copy, but the thing copied is only the route to the object, not the object.
Student std1 = new Student("Ana");
Student std2 = std1;
// std1.getName() returns Ana
// std2.getName() returns AnaBoth variables refer to one object whose name is Ana
Student std1 = new Student("Ana");
Student std2 = std1;
std2.setName("Cara");
// std1.getName() returns Cara
// std2.getName() returns CaraThe change made through std2 is visible through std1, because both read the same object
Comparing References Versus Comparing Contents
The same reference-based behavior affects equality tests. You can use the operators == and != on object variables, but they do not ask whether two objects have the same contents. The values stored in the two variables are references, and == compares those references. So an expression such as std1 == std2 answers one question only: do these two variables refer to the same object?
To compare the contents of two objects, you compare their instance variables individually. For String fields, use the equals method rather than ==, as in name.equals(other.name). Which check you need depends on the question your program is asking.
| Question being asked | Operator or method | What it compares |
|---|---|---|
| Do two variables refer to the same object? | == | The stored references |
| Do two objects hold the same name? | name.equals(other.name) | The contents of the name field |
| Are two objects at different locations with equal contents? | == on references returns false, equals on fields can return true | References versus field values |
Reference comparison and content comparison answer different questions
false
true- a and b are two different objects, each created by its own new operation
- == compares the two references, which point to different objects, so the result is false
- equals compares the String contents of the name fields, which match, so the result is true
Mistakes Learners Make With Object Variables
Common mistake Believing that assigning one object variable to another makes a separate copy of the object
What it looks likeStudent b = a; then b.setName("Cara") and expecting a.getName() to still return the old name
Why it failsThe assignment copies the reference stored in a, not the object. Both variables lead to the same object.
Do this insteadRead the assignment as making a second name for the same object, and expect field changes to be shared.
Common mistake Describing the object as stored inside the variable
What it looks likeSaying the Student is inside the box named std
Why it failsThe variable holds a reference that points to an object in the heap; the object is not contained in the variable.
Do this insteadSay that std refers to the Student object.
Common mistake Using == to check whether two objects have the same contents
What it looks likea == b returning false for two Student objects that both hold the name AnaWhy it fails== compares references, so it only reports whether both variables refer to the same object.
Do this insteadCompare the instance variables individually, using equals for String fields.
Common mistake Calling the constructor as a separate step after new, rather than understanding that new invokes the constructor as part of creating the object
Tracing a Sequence of Object Statements
Before running any code, trace the following sequence on paper. For each variable, write down which object it refers to after each line, and note whether two variables now share one object. Use the labels obj1 and obj2 for the two objects created by new.
Given these statements: Student p = new Student("Ana"); Student q = new Student("Ben"); Student r = p; r.setName("Dee"); q = r; After the last line, which object does q refer to, what does p.getName() return, and does q == p evaluate to true? Trace each variable before answering.
Hints
- Each new operator creates a separate object, so p and q start by referring to different objects
- The statement r = p copies the reference in p, so r and p share one object
- Reassigning q with q = r replaces the reference stored in q; it does not change the object that q used to refer to
Key Takeaways About References
- 1An object variable holds a reference that points to an object; it does not contain the object
- 2The new operator creates an instance of a class, invokes its constructor, and returns a reference to the new object
- 3Assigning one object variable to another copies the reference, so both variables refer to the same object and share its field changes
- 4The == and != operators compare references, while comparing contents requires comparing instance variables, using equals for String fields
At a glance
- An object variable holds a reference, also called a pointer, that identifies where the object lives in the heap. The variable is not a box that contains the object.
- The new operator creates an object that is an instance of a class, calls the class's constructor as part of that creation, and returns a reference to the object.
- Assigning one object variable to another copies the reference, so both variables refer to the same object and a field changed through one is visible through the other.
- The == and != operators compare references, so they answer whether two variables refer to the same object. To compare contents, compare instance variables individually, using equals for String fields.