1. Overview

In this tutorial, we’re going to have a closer look at the covariant return type in Java. Before examining covariance from the return type’s point of view, let’s see what that means.

2. Covariance

Covariance can be considered as a contract for how a subtype is accepted when only the supertype is defined.

Let’s consider a couple of basic examples of covariance:

List<? extends Number> integerList = new ArrayList<Integer>();

List<? extends Number> doubleList = new ArrayList<Double>();

So covariance means, we can access specific elements defined via their supertype. However, we aren’t allowed to put elements into a covariant system, since the compiler would fail to determine the actual type of the generic structure.

3. The Covariant Return Type

The covariant return type is – when we override a method – what allows the return type to be the subtype of the type of the overridden method.

To put this into practice, let’s take a simple _Producer _class with a produce() method. By default, it returns a _String _as an _Object _to provide flexibility for the child classes:

public class Producer {

public Object produce(String input) {

Object result = input.toLowerCase();

return result;



As a result of the _Object _as a return type, we can have a more concrete return type in the child class. That will be the covariant return type and will produce numbers from character sequences:

public class IntegerProducer extends Producer {


public Integer produce(String input) {

return Integer.parseInt(input);




The Covariant Return Type in Java
1.45 GEEK