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, its collection of variables is stored contiguously in some location in memory. That location in memory (the address) is what we call the object’s reference. 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 varibles does not refer to an object.

  • The location of an object in memory.

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 any reference type, and it is used to denote that the variable does not currently refer to a valid object (so it does not have contain a memory address). Therefore, we might say that variable sue does not currently refer to any object as the variable contains null.

Under the Hood: Remember, sue is an alias for some location in the computer’s primary memory (RAM). Since using the variable name is more readable and does not require us to choose an arbitrary address, it is more common to diagram this using the variable name. The diagram below demonstrates this idea by showing the variable name (alias) and its current value (null).

scale 1.5

object sue {
    null
}

Example 2: Refer to Some Object

Now consider the following declaration/initialization:

1Person sue;
2sue = 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:

  1. the variable sue is declared with Person as its type (line 1);

  2. a Person object is constructed (starting with new on line 2); and

  3. the object’s reference (memory address) is assigned to sue (using = on line 2).

Since the value of sue is now a reference to some Person object, we say that sue refers to the Person object.

Under the Hood: Let 12048 denote the memory location of the constructed Person object. Please note that this value is arbitrary as we cannot predict the actual memory address when the code is running. You could make up any number you like to put here.

The diagram below shows the Person object located at address 12048, denoted : Person@12048. The : indicates an object and @12048 indicates the location of that object in memory.

    scale 1.5

object ": Person@12048" as Person0 {
   name = "Sue"
   age = 19
}

object sue {
   12048
}

sue -right-> Person0

Important

Pay close attention to fact that variable sue does not store the object’s contents. Instead, sue is the address where the Person object resides in memory (12048).

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 reference in the value of sue can change over time, the calling object can also change.

Test Yourself

Consider the following initializations:

1Person sue = new Person("Sue", 19);
2Person 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. You can come up with arbitrary memory addresses as needed.

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 very 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:

  1. the variable sally is declared with Person as its type;

  2. the value of sue (a memory address) is retrieved by the computer; then

  3. the 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.

Note

There is only one object created. You can tell because the keyword new is only used once. Assigning the value of sue to sally does not make a copy of the object - only the address of the object.

It may seem strange that the sally variable refers to an object that has the string “Sue” assigned as the name. In fact, the programmer may not have intended to do this. Just keep in mind that Java does what we ask it to do – even if it feels weird to us. It’s up to us to understand the rules of the language!

In our solution, we changed the memory address of the Person object to 78241, but any number is allowed.

       scale 1.5

   object ": Person@78241" as Person0 {
            name = "Sue"
            age = 19
       }

       object sue {
        78241
   }

       object sally {
        78241
   }

       sue -right-> Person0
       sally -right-> Person0

This is an interesting scenario because the calling object for sue and the calling object for sally now refer to the same object!

Test Yourself

Consider the following code:

1Person joe = new Person("Joe", 37);
2Person chris = joe;
3
4chris.setName("Chris"); // assume the setName method exists and changes the name of the calling object.
5System.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!

Test Yourself Solution (Don’t open until completing the question above)

The first two lines of code are similar to the previous question (with the names changed). After line 2 executes, our diagram would look like this:

    scale 1.5

object ": Person@178" as Person0 {
       name = "Joe"
   age = 37
    }

object joe {
   178
}

object chris {
   178
}

joe -right-> Person0
chris -right-> Person0

When we execute line 3 (chris.setName("Chris")), we are changing the object at memory address 178 (our calling object) since that’s the address stored in variable chris. Our updated diagram should look like this:

    scale 1.5

object ": Person@178" as Person0 {
       name = "Chris"
   age = 37
    }

object joe {
   178
}

object chris {
   178
}

joe -right-> Person0
chris -right-> Person0

When we execute line 4 (System.out.println(joe.getName());), we are getting the name of the object at line 178 (our calling object) because that’s the value in variable joe. So, our output will be Chris.

Rapid Fire Review
  1. What is stored in a reference variable in Java?

    1. The actual object.

    2. The memory address where the object is stored.

    3. The class type of the object.

    4. The size of the object in memory.

  2. In the following declaration, what does the variable s store?

    Scanner s = null;
    
    1. A reference to an object of type Scanner.

    2. The value null, indicating that s does not refer to any object.

    3. The specific memory location 800.

    4. The Scanner class.

  3. Given the following code, what happens when the second line executes?

    Scanner s;
    s = new Scanner(System.in);
    
    1. A new Scanner object is created, and its reference is assigned to s.

    2. The value null is assigned to s.

    3. The Scanner object is destroyed.

    4. The value of s is set to an arbitrary memory address.

  4. In the memory diagram below, what does the line from s to the Scanner object represent?

      +--+     +----------------+
    s | -|----◆|                |
      +--+     |                |
               +----------------+
    

    scale 1.5

object ": Scanner" as Scanner0 {
    Scanner object contents...
}

object s

s -right-> Scanner0

    1. The actual Scanner object.

    2. The method that s calls.

    3. The reference stored in s that points to the Scanner object.

    4. The size of the Scanner object in memory.