Reference VariablesJ8 Home « Reference Variables

Java comes with two types of variables to choose from, primitives and reference. In this lesson we look at reference variables and how to use them in Java. We discussed primitive variables in the Fundamentals section in the Primitive Variables lesson.

Reference variables are concerned with objects and how we access them. The reference variable doesn't hold the object itself but some bits that act as a pointer to an address in memory where the object exists. How the JVM holds these bits isn't important for us as developers, just the fact that this memory address pointer is used by the JVM to access a unique object. There are three steps involved in object creation:

object creation
Figure 1. Typical object creation.

So lets go through the three step process above:

  1. Declaration - Here. we declare a reference variable named moggy of type Cat and the JVM allocates space for it.
  2. Creation - Tells the JVM to allocate space on The Heap for a new Cat object.
  3. Assignment - Assign the new Cat object to the reference variable moggy.

The new Operator Top

As you can see from the diagram above object creation is a three step process involving declaration, creation and assignment. We create objects using the new operator which allocates space on the heap for an existing reference variable or one declared at instantiation:


package info.java8;
/*
  Examples of class instantiation
*/ 
public class Testinstanceof {

    public static void main (String[] args) {
        Cat moggy = new Cat();    // Declare, create and assign Cat instance
        
        Cat moggy2;   // Declare Cat reference
        moggy2 = new Cat();   // Allocate and assign Cat instance
    } 
}

The Heap Top

The Heap is the area of memory that the JVM allocates to store our objects in. As long as we have a reference to an object then it exists on the Heap. Of course computer memory is finite and so the JVM needs to discard objects on the Heap and call the finalize() method of the Object class, when their scope ends and there are no live references to them, or they become unreachable: this is known as garbage collection (GC). Setting a reference to null will also deprogram it from any object; in fact trying to access a null pointer will cause a NullPointerException runtime error. To clarify this lets go through the creation of some objects and see what happens to them on the Heap and when they become eligible for GC. The following slide show depicts a scenario, just press the buttons to step backwards and forwards.

heap 1

In this slide we create 3 Cat objects and these are placed on the Heap and can be accessed through their reference variables.


heap 2

In this slide we assign the reference variable tabby to reference variable tigger. This means that the Cat object that was previously referenced by tabby is now unreachable and as such is eligible for GC. tigger and tabby now refer to the same Cat object.

heap 3

In this slide we assign the reference variable tigger to reference variable moggy and so moggy and tigger now refer to the same Cat object. This also means that the Cat object that was previously referenced by tigger is now only referenced by tabby.

heap 4

In this slide we assign null to the reference variable moggy and so the pointer in this reference variable refers to nothing. tigger still refers to the Cat object that moggy previously did.

heap 5

In this final slide we assign null to the reference variable tigger and so the pointer in this reference variable refers to nothing. This means that the Cat object that was previously referenced by tigger is now unreachable and as such is eligible for GC.

Lets look at some code to illustrate the above scenario:


package info.java8;
/*
  Test Class2 for Cat
*/ 
public class TestCat2 {

    public static void main (String[] args) {
        Cat moggy = new Cat();    // Create a Cat instance
        Cat tigger = new Cat();   // Create a Cat instance
        Cat tabby = new Cat();    // Create a Cat instance
        tabby = tigger;    
        tigger = moggy;    
        moggy = null;    
        tigger = null;    
        tabby.talk();             // execute the talk() method
        tigger.talk();            // execute the talk() method (runtime error)
    }
}

Running the TestCat2 class produces the following output:

run heap
Screenshot 1. Running the TestCat2 class.

The assignments of the reference variables happen as in the slide show. tabby can talk as his reference variable still points to a Cat object on the heap. When we try and get tigger to talk we get a NullPointerException runtime error as this reference is now null.

The Stack Revisited Top

In the Fundamentals section in the Method Scope lesson we took our first look at the Stack and used primitive local variables for our examples. What we haven't mentioned so far is reference variables and the Stack. The rules for local variables that are reference variables are the same as local variables that are primitives. The following slide show shows this in action, just press the buttons to step backwards and forwards.

So to summarize, a local variable, whether primitive or reference, is alive as long as its method exists on the Stack. You can only use a methods local variables while the method is at the top of the stack (is executing).

The instanceof Operator Top

We looked at operators in great detail in the Operators and Bitwise Operators lessons of the Fundamentals section of the site. There was an admission from the list, the instanceof operator, which we will discuss now as this operator can only be used with reference variables. We use the instanceof operator to find out whether an object is of a particular type. Because Java is a strongly typed language, it cares about the type of the variables we declare and try to use. So just be aware when using the instanceof operator to check for a String object, when you have an instance of Monkey that knows nothing about String, you will get a compiler error.


package info.java8;
/*
  Test Class for instanceof Operator
*/ 
public class Testinstanceof {

    public static void main (String[] args) {
        Cat moggy = new Cat();
        if (moggy instanceof Cat) {;   // Check for Cat instance
            System.out.println("moggy is a Cat.");
        } 
    } 
}

Running the Testinstanceof class produces the following output:

run runinstanceof
Screenshot 2. Running the Testinstanceof class.

The screenshot shows the output from the Testinstanceof test class, showing that moggy is indeed a Cat.

We can also use the instanceof operator with polymorphic types and this is discussed in Using instanceof With Interfaces.

Related Quiz

Objects & Classes Quiz 4 - Reference Variables

Lesson 4 Complete

In this lesson we looked at reference variables.

What's Next?

We have used methods throughout the lessons so far so its time for a thorough investigation of what we can do with these members.