Covariant return type in java

Covariant method overriding is a powerful feature of Java which was introduced in Java 5. Many programmers don’t know about the covariant return type in java. In this article, we will discuss what is Covariant method overriding and how to implement it?
Before moving forward, you should read about the method overriding in Java and the rules of the method overriding.

As we have already learned the method overriding. In method overriding we can define the method in child class that is already defined in parent classes. Make sure the signature and return type must be the same. That was true only before Java 5.

In Java 5, The covariant return types are newly introduced. After introduced the covariant return type, Java allows us to change the return type of the overriding method(Method in child class). But the return type of overriding method (Method of child class) must be a subtype of the overridden method (Method of Parent class). If you try to provide the return type of overriding method(Method of child class) with supertype, then it with throw exception at compile time.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

class Student
{
	public ArrayList<String> listOfName()
	{
		ArrayList<String> listOfName = new ArrayList<String>();
		listOfName.add("John");
		listOfName.add("Ram");
		listOfName.add("Mary");
		
		return listOfName;
	}
}

public class Record extends Student
{
	public List<String> listOfName()
	{
		List<String> listOfName = new ArrayList<String>();
		listOfName.add("Java");
		listOfName.add("Goal");
		listOfName.add("WebSite");
	
		return listOfName;
	}
	public static void main(String arg[])
	{
		Record record = new Record();
		record.listOfName();
	}
}

Output: Exception in thread “main” java.lang.Error: Unresolved compilation problem: The return type is incompatible with Student.listOfName() at create.Record.listOfName(Record.java:22) at create.Record.main(Record.java:34)

In the above example, we have two classes Student(Parent class) and Record(Child class). The Record class inheriting the method from the Student class. The Student class (Parent class) having the listOfName() method and its return type is ArrayList<String>. This method is automatically inherited in the Record class. In Record class, we are overriding the listOfName() method but its return type is List<String>. Which is not possible because List is the Parent of ArrayList.

We can return only the sub type. Let’s see in below example:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

class Student
{
	public List<String> listOfName()
	{
		ArrayList<String> listOfName = new ArrayList<String>();
		listOfName.add("John");
		listOfName.add("Ram");
		listOfName.add("Mary");
		
		return listOfName;
	}
}

public class Record extends Student
{
	public ArrayList<String> listOfName()
	{
		ArrayList<String> listOfName = new ArrayList<String>();
		listOfName.add("Java");
		listOfName.add("Goal");
		listOfName.add("WebSite");
	
		return listOfName;
	}
	public static void main(String arg[])
	{
		Record record = new Record();
		System.out.println(record.listOfName());
	}
}

Output: [Java, Goal, WebSite]

covariant return type in java

Advantage of covariant return type in java

The Covariant method overriding provides a way that you can return the subtype of actually return type of overridden method. It helps the programmer to remove the burden of type casting. This method is mostly used when the overriding method returns an object.

Let’s understand it with an example. You must have seen the working of clone() method in Java classes. If you are not familiar with working of clone() method, then read it from here.

The clone() method returns the object of Object class. But we can return the object of our own class because every class is the child of Object class. Suppose the Covariant method overriding concept has not introduced yet. Then we need to cast the object every time.
Let’s see in example:

import java.util.ArrayList;
class Student implements Cloneable
{
	int rollNo;
	String className;
	String name;
	
	public int getRollNo() {
		return rollNo;
	}

	public void setRollNo(int rollNo) {
		this.rollNo = rollNo;
	}

	public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	
	public Student(int rollNo, String className, String name) 
	{
		this.rollNo = rollNo;
		this.className = className;
		this.name = name;
	}
	
	public void printData()
	{
		System.out.println("Name : " + name + ", RollNo: "+ rollNo + ", Class Name : "+ className);
	}

	@Override
	public Object clone() throws CloneNotSupportedException
	{
		return super.clone();
	}
}

public class MainClass
{
	public static void main(String arg[]) throws CloneNotSupportedException
	{
		Student student1 = new Student(1, "MCA", "Ram");
		student1.printData();
		
		Student student2 = (Student) student1.clone();
		student2.setName("Ravi");
		student2.setRollNo(2);
		student2.printData();
	}
}

Output: Name : Ram, RollNo: 1, Class Name : MCA
Name : Ravi, RollNo: 2, Class Name : MCA

In the above example when we are using the clone() method, it returns the object of Object class and then we typecast it into Student class.

Student student2 = (Student) student1.clone();

Suppose we are using the clone method 10 times in the program then we need to typecast it every time. To overcome these types of problem we can Covariant method overriding. By use of Covariant concept, we can return the object of the Student class instead of Object class.
Let’s see how we can use it.

import java.util.ArrayList;
class Student implements Cloneable
{
	int rollNo;
	String className;
	String name;
	
	public int getRollNo() {
		return rollNo;
	}

	public void setRollNo(int rollNo) {
		this.rollNo = rollNo;
	}

	public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	
	public Student(int rollNo, String className, String name) 
	{
		this.rollNo = rollNo;
		this.className = className;
		this.name = name;
	}
	
	public void printData()
	{
		System.out.println("Name : " + name + ", RollNo: "+ rollNo + ", Class Name : "+ className);
	}

	@Override
	public Student clone() throws CloneNotSupportedException
	{
		return (Student) super.clone();
	}
}

public class MainClass
{
	public static void main(String arg[]) throws CloneNotSupportedException
	{
		Student student1 = new Student(1, "MCA", "Ram");
		student1.printData();
		
		Student student2 = student1.clone();
		student2.setName("Ravi");
		student2.setRollNo(2);
		student2.printData();
	}
}

Output: Name : Ram, RollNo: 1, Class Name : MCA
Name : Ravi, RollNo: 2, Class Name : MCA

You can see above, we don’t need to typecast object returned from clone() method to Student, because we are returning an object of Student class instead of Object class.

Leave a Comment