Covariant Return Types in Java with Example

Covariant Return types in Java | As you know that in the overriding, the return type of subclass method must be the same as the superclass method return type.

But this rule is applicable until Java 1.4 version. In Java 1.5, a new covariant return types feature was introduced.

By using this feature, it is possible to override any method by changing the return type only if the return type of overriding method in the subclass is a subtype of the declared return type of overridden method instead of being exactly the same type. It is known as covariant return types in Java.

Key Points:

1. The return type of overriding method in the subclass should be either the same as the return type of superclass or subclass.
2. The return type of overriding method in the subclass should not be a parent of the parent method return type.
3. The covariant return type is applicable only for object types not for primitive types.


Covariant return type in Java

Java Covariant return types Example Program


Let’s take various types of example programs based on covariant return types in Java.

Program source code 1:

package covariantReturnType; 
public class A 
{ 
 public Object m1()
 { 
   System.out.println("Hello, this is a superclass"); 
    return null; 
  } 
} 
public class B extends A
{ 
 @Override 
  public String m1() 
  { 
     System.out.println("Hello, this is the subclass"); 
      return null; 
  } 
 } 
public class AB 
{ 
  public static void main(String[] args) 
  { 
     B b = new B(); 
      b.m1(); 
     A a = new B(); 
      a.m1(); 
   } 
 }
Output: 
       Hello, this is the subclass 
       Hello, this is the subclass

Explanation:

In the above example program, superclass declares m1() method of Object return type and B class overrides the m1() method by changing the return type from Object to String.


The return type of the overriding method m1() in the subclass is a string that is the subclass of an object class.

1. b.m1() will call m1() method of class B because the reference variable is pointing to the objects of class B. As you learned from the previous tutorial that in overriding, method resolution always takes care by JVM based on the runtime object.

2. Similarly, a.m1() will also call m1() method of class B because it is also pointing to the object of class B.

Program source code 2:

package covariantReturnType; 
public class A 
{ 
 public String m1()
 { 
    System.out.println("Hello, this is a superclass"); 
     return null; 
  } 
 } 
public class B extends A
{ 
  @Override 
 public Object m1() // Return type of overriding method is incompatible with A.m1() because the return type of overriding method in the subclass should not be parent. Here, Object is the parent class of String. Therefore, it is not an overridden method.
 { 
    System.out.println("Hello, this is the subclass"); 
     return null; 
  } 
} 
public class AB 
{ 
  public static void main(String[] args) 
  { 
    A a = new B(); 
     a.m1(); 
   } 
 }
Output: 
       Hello, this is a superclass

Because of not being overriding in the subclass, a.m1() will call by default available m1() method in class B.

Program source code 3:

package covariantReturnType; 
public class A 
{ 
 public Number m1(int a, double b)
 { 
   System.out.println("Hello, this is a superclass"); 
    return null; 
  } 
} 
public class B extends A
{ 
  @Override public Integer m1(int a, double b)
  { 
    System.out.println("Hello, this is the subclass"); 
     return null; 
  } 
} 
public class AB 
{ 
  public static void main(String[] args) 
  { 
     A a = new B(); 
     a.m1(10,20.5); 
  } 
 }
Output: 
        Hello, this is the subclass

Program source code 4:

package covariantReturnType; 
public class X 
{ 
  public Object m1(char c)
  { 
    System.out.println("m1-X"); 
     return new X(); 
  } 
} 
public class Y extends X
{ 
  @Override 
  public StringBuffer m1(char c)
  { 
    System.out.println("m1-Y"); 
     return null; 
   } 
} 
public class XY 
{ 
  public static void main(String[] args) 
  { 
    X x = new Y(); 
    x.m1('a'); 

    X x1 = new X(); 
    x1.m1('b'); 
   } 
}
Output: 
       m1-Y 
       m1-X

Program source code 5:

package covariantReturnType; 
public class X 
{ 
  public double m1(char c)
  { 
    System.out.println("m1-X"); 
      return 25; 
   } 
} 
public class Y extends X
{ 
  @Override 
  public Integer m1(char c) // Error because the return type is incompatible with X.m1(char). Covariant return type concept is applicable only for an object reference type, not for primitive types because there is no subtype relationship between primitive types. 
  { 
     System.out.println("m1-Y"); 
      return 20; 
   } 
} 
public class XY 
{ 
  public static void main(String[] args) 
  { 
     X x = new Y(); 
      x.m1('a'); 
     X x1 = new X(); 
      x1.m1('b'); 
   } 
 }
Output: 
       m1-X 
       m1-X

Because of not being overriding in the subclass, x.m1(‘a’) will call by default available m1() method in class Y. Similarly, x1.m1(‘b’) will call m1() method of class A because reference variable x1 is pointing to the objects of class A.

Now, suppose if we declare also double as the return type of the overriding method in the subclass as in the superclass then there will not be a compile-time error. So, in this case, the method will be overriding. The result will be “m1-Y” and “m1-X”.

Hope that this tutorial has covered covariant return types in Java with example program. I hope that you will have understood this topic and enjoyed it.

Key Points to Remember:

1. Java SE5 adds a new feature Covariant return types which means we can override any method by changing return type if the return type of subclass overriding method is subclass type.

2. Covariant return type also helps to minimize upcasting and downcasting in Java.

Thanks for reading!!!

Leave a Comment