Table of contents
1.
Introduction
2.
Understanding Reference Variables in Java
2.1.
Java
3.
Benefits & Usage of Reference Variables
4.
Reference Variable as Method Parameters
4.1.
Example: Modifying Object Attributes
4.2.
Java
5.
Advantages of Using Reference Variables as Parameters
5.1.
What if We Swap the Reference Variables with the Help of the Swap Method?
6.
Example: Attempting to Swap Objects
6.1.
Java
7.
Why Doesn't the Swap Persist?
8.
Example: Modifying an Array Within a Method
8.1.
Java
8.2.
In this code
8.3.
Key Takeaways
9.
This & Super Keywords are Also Pointing Elements
9.1.
Understanding the this Keyword
9.2.
Understanding the super Keyword
9.3.
Java
10.
This & Super Keywords are Also Pointing Elements
10.1.
Understanding the this Keyword
10.2.
Understanding the super Keyword
10.3.
Java
10.4.
Key Benefits of Using this and super
11.
Null Value of a Reference Variable
11.1.
What Happens When a Reference Variable is Null?
11.2.
Example: Safe Handling of Null References
11.3.
Java
11.4.
Importance of Handling Null Values
12.
Frequently Asked Questions
12.1.
What happens if you try to access a method on a null reference variable?
12.2.
Can reference variables be used with all data types in Java?
12.3.
How can you ensure that a reference variable is not null before using it?
13.
Conclusion
Last Updated: Sep 2, 2024
Easy

Reference Variable in Java

Author Pallavi singh
1 upvote

Introduction

In Java, a reference variable is a type of variable that holds the memory address of an object. It acts as a pointer to the object's location in memory, allowing you to access & manipulate the object's data & behavior. Reference variables are essential for working with objects & creating dynamic, flexible programs. Unlike primitive data types that hold their values directly, reference variables store the address of the object they refer to, enabling the manipulation of objects through these references. 

Reference Variable in Java

In this article, we will learn about the concept of reference variables, their benefits, & various scenarios where they could be useful.

Understanding Reference Variables in Java

In Java, when you create an object, the system allocates memory for it and assigns a reference to it. A reference variable is essentially a label that points to this memory location where the object is stored. Unlike primitive types such as int or double, which store actual values, reference variables store the addresses of the objects they refer to. This allows multiple variables to reference the same object, leading to more flexible and dynamic code management.

For example, consider the following Java code where two reference variables point to the same object:

  • Java

Java

class Car {

String color;


Car(String color) {

this.color = color;

}

}

public class Test {

public static void main(String[] args) {

Car myCar = new Car("Red");

Car anotherCar = myCar;

anotherCar.color = "Blue";

System.out.println(myCar.color); // Outputs "Blue"

}

}
You can also try this code with Online Java Compiler
Run Code

Output

Blue

In this example, myCar and anotherCar are reference variables that point to the same Car object. When anotherCar changes the color of the car to "Blue", myCar sees this change too because both reference variables point to the same object. This illustrates how reference variables work: they don't hold the data themselves but rather a way to access that data.

Benefits & Usage of Reference Variables

Reference variables in Java are powerful tools because they allow programmers to control and manage objects efficiently. Here are some of the key benefits and uses of reference variables:

  1. Memory Management: By using reference variables, Java programs can share and reuse objects. This saves memory because you don’t need to create a new object each time you need similar functionality. Instead, you can use a reference to an existing object.
     
  2. Flexibility in Code: Reference variables enhance the flexibility of code. You can pass references to methods and thus allow those methods to modify the original objects, which is much more efficient than passing copies of objects.
     
  3. Implementing Data Structures: Complex data structures such as linked lists, trees, and graphs are implemented using reference variables. These structures involve nodes or elements that point to other elements, creating a chain or a network of objects linked through references.

For instance, in the implementation of a linked list, each node in the list holds a reference to the next node, making it possible to traverse and manipulate the list via these references.

Here’s a simple example to demonstrate:

class Node {
    int data;
    Node next;
    Node(int data) {
        this.data = data;
        this.next = null;
    }
}
public class LinkedList {
    Node head; // reference to the head of the list
    public void add(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            head = newNode;
        } else {
            Node current = head;
            while (current.next != null) {
                current = current.next;
            }
            current.next = newNode;
        }
    }
    public void printList() {
        Node current = head;
        while (current != null) {
            System.out.println(current.data);
            current = current.next;
        }
    }
}


In the above example, the LinkedList class uses reference variables (head and current) to track and manipulate nodes in the list. This shows how essential reference variables are for managing dynamic, interconnected data structures.

Reference Variable as Method Parameters

One of the practical uses of reference variables in Java is as parameters to methods. This approach is fundamental in scenarios where you need to modify the state of an object within a method. When a reference variable is passed to a method, the method receives not just a value but a reference to the original object. This means any changes made to the object within the method are reflected in the object used to call the method.

Example: Modifying Object Attributes

Consider a scenario where you have a Car class, and you want to update the attributes of a car object through a method. Here’s how you could do it using reference variables:

  • Java

Java

class Car {

   String color;

   int year;

  Car(String color, int year) {

       this.color = color;

       this.year = year;

   }

   // Method to update car's color

   void updateColor(String newColor) {

       color = newColor;

   }

}

public class TestCar {

   public static void main(String[] args) {

       Car myCar = new Car("Red", 2020);

       System.out.println("Original color: " + myCar.color); // Outputs "Red"

       // Pass the car object to the method

       changeCarColor(myCar, "Blue");

       System.out.println("Updated color: " + myCar.color); // Outputs "Blue"

   }

   static void changeCarColor(Car car, String newColor) {

       car.updateColor(newColor);

   }

}
You can also try this code with Online Java Compiler
Run Code

Output

Original color: Red
Updated color: Blue


In the code above, myCar is a reference variable for a Car object. The changeCarColor method takes this reference as an argument and modifies the Car object’s color. Since the method operates on the reference pointing to myCar, the changes are seen outside the method as well.

Advantages of Using Reference Variables as Parameters

  • Efficiency: Passing a reference is more memory-efficient than passing copies of large objects.
  • Functionality: It allows methods to modify the internal states of objects, providing a lot of flexibility in how objects are handled and manipulated.

What if We Swap the Reference Variables with the Help of the Swap Method?

Swapping reference variables in Java demonstrates an interesting behavior when handling objects. Usually, when you attempt to swap objects using their references within a method, the swap does not persist outside the method. This is due to Java's pass-by-value nature, where changes to the reference itself are not reflected outside the method.

Example: Attempting to Swap Objects

Let's explore this with a practical example using a simple Box class that stores an integer. We'll try to swap two Box objects using a method:

  • Java

Java

class Box {

   int value;

   Box(int value) {

       this.value = value;

   }

}

public class TestSwap {

   public static void main(String[] args) {

       Box box1 = new Box(10);

       Box box2 = new Box(20);

       System.out.println("Before swap: box1 value = " + box1.value + ", box2 value = " + box2.value);

       swapBoxes(box1, box2);

       System.out.println("After swap: box1 value = " + box1.value + ", box2 value = " + box2.value);

   }

   static void swapBoxes(Box a, Box b) {

       Box temp = a;

       a = b;

       b = temp;

   }

}
You can also try this code with Online Java Compiler
Run Code

Output

Before swap: box1 value = 10, box2 value = 20
After swap: box1 value = 10, box2 value = 20


In the above code, box1 and box2 are reference variables pointing to Box objects. The swapBoxes method tries to swap them by changing the references a and b. However, after the method executes, you will notice that the values of box1 and box2 remain unchanged outside the swapBoxes method. This is because only the references a and b were swapped inside the method, not the actual links (box1 and box2) to the objects.

Why Doesn't the Swap Persist?

  • Pass-by-Value: Java methods receive parameters by value, even when dealing with objects. What gets passed to the method is a copy of the reference, not the actual reference itself. Therefore, swapping references inside the method does not affect the original references.
     
  • Scope of References: The scope of the references a and b is limited to inside the swapBoxes method. Changes to these references do not impact the original objects outside of this scope.
     

What if We Pass Arrays to the Method Will it Be Able to Update the Actual Array’s Values, Even We Know That a Copy of the Array Is Passed to the Formal Array?

When working with arrays in Java, an interesting aspect is how they are treated when passed to methods. Although Java follows pass-by-value, this rule applies differently to arrays. When you pass an array to a method, you are passing the reference to the array by value. This means the method receives a copy of the reference, not the actual array, but both references (the original and the copy) point to the same actual array in memory.

Example: Modifying an Array Within a Method

Here's how passing an array to a method can affect the array's actual values:

  • Java

Java

public class TestArray {

   public static void main(String[] args) {

       int[] numbers = {1, 2, 3, 4, 5};

       System.out.println("Original array before method call: " + java.util.Arrays.toString(numbers));

       modifyArray(numbers);

       System.out.println("Array after method call: " + java.util.Arrays.toString(numbers));

   }

   static void modifyArray(int[] array) {

       for (int i = 0; i < array.length; i++) {

           array[i] += 5; // Modify each element of the array

       }

   }

}
You can also try this code with Online Java Compiler
Run Code

Output

Original array before method call: [1, 2, 3, 4, 5]
Array after method call: [6, 7, 8, 9, 10]

In this code

numbers is an array that holds several integers.

  • The modifyArray method is designed to take an array as a parameter and modify each element of the array.
     
  • When numbers is passed to modifyArray, what is actually passed is a copy of the reference to the numbers array. This copied reference points to the same original array.
     
  • Changes made in modifyArray are reflected in the original numbers array because both the original reference and the copied reference in the method point to the same array.

Key Takeaways

  • Actual Modification: Modifications to the array within the method affect the original array because the method operates on the same array object to which the original reference points.
  • Memory Efficiency: This behavior is beneficial for memory usage because Java does not create a new array; it simply passes the reference. This is particularly efficient for large arrays or when performance is a concern.

This & Super Keywords are Also Pointing Elements

In Java, the this and super keywords are essential for managing reference variables within class hierarchies. They provide a way to refer to the current object or an object's superclass, facilitating the navigation and manipulation of object properties and methods. Here’s how each keyword functions and how they contribute to Java programming:

Understanding the this Keyword

The this keyword is used within a class to refer to the current instance of that class. It is particularly useful in situations where local variables (such as parameters of a method) have the same names as class field variables (instance variables).

Example of this :

class Rectangle {
    private int width, height;
    public Rectangle(int width, int height) {
        this.width = width;  // Points to the instance variable width
        this.height = height;  // Points to the instance variable height
    }
    public void displayDimensions() {
        System.out.println("Width: " + this.width + ", Height: " + this.height);
    }
}


In the example, this.width and this.height distinguish the instance variables from the parameters of the constructor, both named width and height.

Understanding the super Keyword

The super keyword serves a different purpose—it is used to access methods and variables of a parent (superclass) when subclasses have methods or variables with the same names, or when subclass methods need to invoke superclass methods.

Example  of super:

  • Java

Java

class Shape {

   public void display() {

       System.out.println("Displaying shape");

   }

}

class Circle extends Shape {

   public void display() {

       super.display();  // Calls the display method of Shape

       System.out.println("Displaying circle");

   }

}

public class TestShapes {

   public static void main(String[] args) {

       Circle myCircle = new Circle();

       myCircle.display();

   }

}
You can also try this code with Online Java Compiler
Run Code

Output

Displaying shape
Displaying circle

This & Super Keywords are Also Pointing Elements

In Java, the this and super keywords are essential for managing reference variables within class hierarchies. They provide a way to refer to the current object or an object's superclass, facilitating the navigation and manipulation of object properties and methods. Here’s how each keyword functions and how they contribute to Java programming:

Understanding the this Keyword

The this keyword is used within a class to refer to the current instance of that class. It is particularly useful in situations where local variables (such as parameters of a method) have the same names as class field variables (instance variables).

Example Usage of this:

class Rectangle {
    private int width, height;
    public Rectangle(int width, int height) {
        this.width = width;  // Points to the instance variable width
        this.height = height;  // Points to the instance variable height
    }
    public void displayDimensions() {
        System.out.println("Width: " + this.width + ", Height: " + this.height);
    }
}


In the example, this.width and this.height distinguish the instance variables from the parameters of the constructor, both named width and height.

Understanding the super Keyword

The super keyword serves a different purpose—it is used to access methods and variables of a parent (superclass) when subclasses have methods or variables with the same names, or when subclass methods need to invoke superclass methods.

Example Usage of super:

  • Java

Java

class Shape {

   public void display() {

       System.out.println("Displaying shape");

   }

}

class Circle extends Shape {

   public void display() {

       super.display();  // Calls the display method of Shape

       System.out.println("Displaying circle");

   }

}

public class TestShapes {

   public static void main(String[] args) {

       Circle myCircle = new Circle();

       myCircle.display();

   }

}
You can also try this code with Online Java Compiler
Run Code

Output

Displaying shape
Displaying circle


In this code, super.display() is used in the Circle class to call the display() method of its superclass Shape. This allows Circle to extend the functionality of the display() method without overriding it completely.

Key Benefits of Using this and super

  • Clarity and Avoidance of Name Conflicts: These keywords help clarify which variables and methods are being referred to, preventing errors and confusion in more complex classes and hierarchies.
     
  • Enhanced Reusability and Modularity: They allow classes to be written in a way that enhances their reusability and modularity by neatly segregating parent and child class behaviors.

Null Value of a Reference Variable

In Java, the null value plays a crucial role when dealing with reference variables. It represents the absence of a reference to any object. A reference variable that holds the null value is effectively pointing to nothing. This is particularly important in scenarios where you need to check whether a reference has been assigned to an actual object or not, thus avoiding potential errors such as NullPointerException.

What Happens When a Reference Variable is Null?

When a reference variable is set to null, it means that it does not refer to any object. Attempting to access or manipulate an object through a null reference will lead to a NullPointerException, one of the most common errors in Java programming. This can be prevented by properly checking if a reference variable is null before using it.

Example: Safe Handling of Null References

  • Java

Java

public class Person {

   String name;

   public Person(String name) {

       this.name = name;

   }

   public void printName() {

       if (this.name != null) {

           System.out.println("Name: " + this.name);

       } else {

           System.out.println("Name is not available.");

       }

   }

}

public class TestNull {

   public static void main(String[] args) {

       Person person = new Person(null);

       person.printName();  // Safely checks and handles null

       Person anotherPerson = null;

       if (anotherPerson != null) {

           anotherPerson.printName();

       } else {

           System.out.println("No person data to display.");

       }

   }

}
You can also try this code with Online Java Compiler
Run Code

Output

Name is not available.
No person data to display.


In this code:

  • person is an instance of Person whose name is explicitly set to null. The method printName() checks for null before attempting to print the name, thus avoiding a NullPointerException.
  • anotherPerson is set to null. Before calling printName(), we check if anotherPerson is not null to ensure that we avoid accessing methods on a null reference.

Importance of Handling Null Values

  • Prevents Runtime Errors: Checking for null before accessing methods or fields on an object helps prevent runtime exceptions, which can cause programs to crash.
  • Improves Program Stability: Proper null checks make the program more robust and stable by explicitly handling the cases where data may not be available.

Frequently Asked Questions

What happens if you try to access a method on a null reference variable?

Attempting to call a method on a null reference variable will result in a NullPointerException. This occurs because there is no actual object to invoke the method on, highlighting the importance of null checks in your code.

Can reference variables be used with all data types in Java?

Reference variables can only be associated with objects and arrays, not primitive data types like int, double, or boolean. Primitive types are stored directly in their corresponding variables.

How can you ensure that a reference variable is not null before using it?

To prevent NullPointerException, always check if a reference variable is null by using a condition such as if (variable != null) before you attempt to access its properties or methods.

Conclusion

In this article, we have learned the concept of reference variables in Java, their benefits, usage, and critical role in memory management and code flexibility. We discussed their practical aspects such as using reference variables as method parameters, the behaviour of Java when passing arrays and swapping reference variables, and the importance of this and super keywords in object-oriented programming. We also discussed the implications of null values and provided strategies to safely handle them.

You can refer to our guided paths on Code360. You can check our course to learn more about DSADBMSCompetitive ProgrammingPythonJavaJavaScript, etc. Also, check out some of the Guided Paths on topics such as Data Structure andAlgorithmsCompetitive ProgrammingOperating SystemsComputer Networks, DBMSSystem Design, etc., as well as some Contests, Test Series, and Interview Experiences curated by top Industry.

Live masterclass