1.3. Reference Type Examples¶
For the examples in this section, you should assume access to a class
called Person (which defines the Person reference type) that
has the following declaration:
public class Person {
// instance variables
private String name;
private int age;
// constructor
public Person(String name, int age) {
this.name = name;
this.age = age;
} // Person
// assume getter and setter methods exist...
} // Person
In Java, the reference types ([4.3]) are class types, interface types, and array types. Of these three, you are likely familiar with declaring variables of both class and array types. Interfaces will be covered later in this course.
Below are two example declarations of reference type variables:
Person ada; // A class type variable (valid because we have a class called Person)
double[] array; // An array type variable
An object is really just a collection of variables and methods
that are defined by a class. It is not uncommon to describe Java
objects as dynamically constructed instances of a class. This
means that an object is constructed using the class as a blueprint
when the keyword new is encountered (while the program is running).
When an object is constructed, it is stored on the heap along with its
instance variables, and the expression that constructed it evaluates to
a reference: a value that refers to the new object. In Java, the
possible values of a reference type are references to compatible
objects or null.
Note
A reference variable either stores:
null- when the variable does not refer to an object.A reference that refers to an object.
Below we describe various scenarios in which you may encounter/use reference variables in your code.
Example 1: Reference variable with a null value
Consider the following declaration and initialization:
Person sue = null;
The variable sue is of type Person and null is its
value. In Java, null is a value that can always be assigned
to a variable of any reference type, and it is used to denote that
the variable does not currently refer to an object. Therefore, we
might say that the value of variable sue is null, which
means sue does not refer to an object.
Under the Hood: Memory diagrams label each variable with its
name rather than with a location in memory. The diagram below
shows the variable name and its current value (null). Since
the value of sue is null, its box shows null and no
arrow leaves it.
Note
The diagram mentions main because this code was run inside
of a main method. The 5 next to main denotes the
line number just after the code seen above. You can ignore the
line number in this example, but it will be useful in more
complex examples.
Example 2: Refer to Some Object
Now consider the following declaration/initialization:
Person sue;
sue = new Person("Sue", 19);
There are three important things that happen in this code, and it's important to note that they happen in the following order:
the variable
sueis declared withPersonas its type;a new
Personobject is constructed; thena reference to the new object is assigned to
sue.
Since the value of sue is now a reference to some Person object,
we say that sue refers to the Person object.
The memory diagram below shows the sue variable, its value, and the
Person object that was created. The value of sue is not the object
itself. That is why the Person object is not in the box where you would
expect the value of sue to be. Instead, it is a reference value that
refers to that object. This is why the relationship between sue and
the object is depicted with an arrow and why the object itself appears
elsewhere.
Important
Pay close attention to the fact that variable sue does not store
the object itself. Instead, the value of sue is a reference that
refers to the Person object. The diagram shows the same number in
the box for sue and in the object's label. That number identifies
the object, so you can see which variables refer to it; it is not a
memory address.
When a method is called using sue (for example, sue.getName()),
the object that sue refers to is known as the calling
object. Non-static methods called using sue are said to operate on
the calling object. Since the value of sue can change over time,
the calling object can also change.
Test Yourself
Consider the following initializations:
Person sue = new Person("Sue", 19);
Person sally = sue;
Before moving on, take a moment to draw a diagram on a sheet of paper that shows how this looks under the hood (sometimes called a memory map or a memory diagram). Use the diagram above as an example. Draw an arrow from each variable to the object it refers to.
Do the best you can before looking at the solution.
Test Yourself Solution (Don't open until completing the question above)
Your drawing should look similar to the previous example with an
extra variable for sally that contains the same value as the variable
sue. We provide the diagram below.
The first line is the same as the previous example. On the second line, three things occur:
the variable
sallyis declared withPersonas its type;the value of
sue(a reference to thePersonobject) is retrieved; thenthe value is assigned to
sally.
Since the value of sally is now the same as the value of sue, we
might say that sue and sally both refer to the same Person
object.
This is an interesting scenario because sue and sally now refer
to the same object, so a method called using either variable has the
same calling object.
Test Yourself
Consider the following code:
Person joe = new Person("Joe", 37);
Person chris = joe;
chris.setName("Chris"); // assume the setName method exists and changes the name of the calling object.
System.out.println(joe.getName());
Take a moment to draw the memory map diagram for the code above. If a line of code changes an instance variable, make sure your diagram reflects that change. Then, write the output from the program in your notes.
Do the best you can before looking at the solution.
Solution (Don't open until completing the question above)
The interactive visualization stepper below illustrates the execution of each statement in sequence:
Notice what occurs at each step of execution:
Step 1: The
joevariable is declared and initialized with a reference to a newly constructedPersonobject on the heap (name="Joe",age=37).Step 2: The reference in
joeis copied tochris. Both variables now refer to the samePersonobject in memory.Step 3: Executing
chris.setName("Chris")modifies the calling object referred to bychris. Becausejoerefers to that same object, the change is reflected when accessing the object throughjoe.Step 4: When
System.out.println(joe.getName())executes, it retrieves the modified name from the shared object and prints Chris.
Rapid Fire Review
What is stored in a reference variable in Java?
The actual object.
A reference to an object, or
null.The class type of the object.
The size of the object in memory.
In the following declaration, what does the variable
sstore?Scanner s = null;
A reference to an object of type
Scanner.The value
null, indicating thatsdoes not refer to any object.The specific memory location
800.The
Scannerclass.
Given the following code, what happens when the second line executes?
Scanner s; s = new Scanner(System.in);
A new
Scannerobject is created, and its reference is assigned tos.The value
nullis assigned tos.The
Scannerobject is destroyed.The value of
sis set to an arbitrary memory address.
The memory diagram below shows the relationship between
sand aScannerobject in a program. The0value that is shown is a placeholder forSystem.in. What does the line fromsto theScannerobject represent?The actual
Scannerobject.The method that
scalls.The reference stored in
sthat refers to theScannerobject.The size of the
Scannerobject in memory.