Monday, August 2, 2021

What is Covariant Method Overriding of Java? Example

Sometimes knowledge of a specific Java feature can improve code quality, Covariant method overriding is one such feature. Covariant method overriding was introduced in Java 5, but it seems it lost between other more powerful features of that release. Surprisingly not many Java programmer knows about Covariant overriding, including me, until I read, one of the best Java books on Collection framework, Java Generics, and Collection. Covariant method overriding helps to remove type casting on the client-side, by allowing you to return a subtype of actually return type of overridden method.

Covariant method overriding can be really useful while overriding methods that returns object e.g. clone() method. Since clone() return object every client needs to cast on to appropriate subclass, not anymore.

By using Java 5 covariant overriding, we can directly return a subtype instead of an object, as we will see in the examples of this article. This feature is not a star feature like Generics or Enum, but it's definitely something worth knowing, given overriding methods are an integral part of Java programming.

I have discussed a bit about this feature earlier in the difference between overriding and overloading articles, and here I will show a couple of more examples to justify its usage.






Covariant Method Overriding Example

As I said, one of the best examples of this is the overriding clone() method, which is declared in java.lang.Object class and has a return type of Object. If you have used java.util.Date in your project and has called its clone method to make a copy, you might know that you need to cast it back to Date as shown below :

Date d = new Date();
Date clone = (Date) d.clone();

wouldn't it be great if the clone() method can return Date instead of Object? Well it can from Java 5 onwards, but unfortunately, code in java.util.Date is not yet updated to take advantage of this, at least till Java 6. Now let's create our own class and override clone() method to demonstrate the use of covariant method overriding in Java.

import java.util.Date;

/** 
  * Java program to demonstrate how to use covariant method overriding to avoid
  * casting at client side.
 
  * @author http://javarevisited.blogspot.com
  */
public class CovariantMethodOverridingTest {

    public static void main(String args[]) {
      
        //without covariant overriding, cast at client side needed
        Date d = new Date();
        Date clone = (Date) d.clone();  //casting required
       
        //with covariant method overriding, no client side cast
        Duck duck = new Duck(0xFFFFFF);
        Duck copy = duck.clone(); //no casting
    }

  
}

class Duck implements Cloneable{
    private int color = 0xFFFFFF;
   
    public Duck(int color){
        this.color = color;
    }
   
    public int getColor(){
        return color;
    }

    @Override
    protected Duck clone() {
        Duck clone = null;
        try{
            clone = (Duck) super.clone();
           
        }catch(CloneNotSupportedException ex){
            throw new RuntimeException(ex);
        }
       
        return clone;
    }  
   
}

You can see in our test program, we don't need to typecast objects returned from the clone() method to Duck, because instead of java.lang.Object, its returning java.util.Date. This is also obvious from looking at the overriding clone() method in Duck class, you can see its return type is Duck, and not Object.

In fact, if you have implemented your own Comparator or Comparable in Java, you can also see that their compare() and compareTo() directly return the type specified in the Type parameter instead of an object. Though this looks like a very small and subtle change, it impacts is huge.

I am sure they will implement the clone() method of java.util.Date sooner or later to take advantage of this feature, unless they decide to deprecate it in favor of new Date and Time API coming in Java 8.


That's all on covariant method overriding of Java 5 guys. Always take advantage of this feature, while the overriding method in Java 5, 6,7, and very soon on Java 8. You can return any subtype, based upon your need. 

All other rules of method overriding remain the same. I know Java is vast, and there are many more features like this, which can be really handy on a day-to-day job but many times remain hidden from a large number of Java developers.

I also suggest reading Java Generics and Collection, a must-read book for any senior Java developer. I always remain in search of hidden gems of Java programming language, API, or third-party library which can make your task easy, can improve code quality, and add value by any means. If you come across any such feature, which you like to share with us, go ahead and comment about it.

Further Learning
Difference between static and dynamic binding in Java
Method Overloading best practices in Java
Difference between bounded and unbounded wildcards in Generics

1 comment:

  1. "if you have implemented your own Comparator or Comparable in Java, you can also see that their compare() and compareTo() directly return the type specified in Type parameter instead of object."

    compare() and compareTo() return Int


    "I am sure they will implement clone() method of java.util.Date sooner or later to take advantage of this feature, unless they decide to deprecate it in favour of new Date and Time API coming in Java 8.
    "

    not yet in jdk1.8.0_05

    ```
    public Object clone() {
    Date d = null;
    try {
    d = (Date)super.clone();
    if (cdate != null) {
    d.cdate = (BaseCalendar.Date) cdate.clone();
    }
    } catch (CloneNotSupportedException e) {} // Won't happen
    return d;
    }
    ```

    ReplyDelete