Javatpoint Logo
Javatpoint Logo

Covariant and Contravariant Java

The ideas of covariance and contravariance come to light in the complex world of Java programming as crucial building blocks for producing durable, flexible, and adjustable software. These ideas, which have their roots in the field of polymorphism, are crucial in determining how types and techniques relate to one another. Knowing the subtleties of covariance and contravariance as developers helps us better comprehend object-oriented principles and create software that can adapt to a variety of contexts.

Covariant in Java

In overriding methods, return types are the main source of covariant interactions in Java. When a subtype offers a more specialized return type than its supertype, this happens. In Java, covariance mostly shows up when it comes to return types in method overriding. Fundamentally, covariance improves the accuracy and expressiveness of our code by enabling a subtype to provide a more precise return type than its supertype.

Example of Covariant

Imagine that a more specialized Dog class overrides a standard Animal class's giveBirth() method with a particular return type of Dog. This complex relationship demonstrates Covariance:


An animal gives birth.
New animal born!
A dog gives birth to puppies.
New dog born!


The giveBirth() function of the Animal class in this code simulates an animal giving birth. The giveBirth() method is superseded by the Dog class, which extends Animal and implements it specifically for dogs. To show how to use these classes, an instance of an Animal and a dog are created in the Main class, and their giveBirth() methods are called.

Contravariant in Java

In contrast to covariant, methods' parameter types are involved in contravariant connections. It happens when a method that is subtyped takes in more generic parameters than its supertype. A fascinating new dimension to our investigation is provided by contravariance, which is the opposite of covariance. Subtypes that have methods that accept more generic parameters than their supertypes come into play with this idea. The flexibility that contravariance gives allows procedures to handle a wider variety of input types with grace.


Consuming: Food@65e579dc
Eating a delicious fruit: Fruit@768debd


This code represents a generic type of food as represented by the Food class and a specific type of food as represented by the Fruit class, which extends Food. A generic class called Consumer has a method for consuming objects of type T. Extending Consumer<Fruit>, the FruitConsumer class is focused on fruit consumption. In order to show how to use these classes, instances of FruitConsumer and Consumer are created in the Main class, and their consumption methods are called.


We have examined the complex interactions between Java types and methods in our examination of covariance and contravariance. Covariance improves expressiveness and refines precision by enabling subtypes to define more precise return types. Subtypes can accept more general parameters thanks to contravariance, which adds flexibility and promotes adaptability.

Contravariant wildcards in generics give an elegant solution for versatile and adaptable classes, while covariant arrays offer versatility but require care. These ideas are essential for developing robust, expandable software that adapts to changing needs. Knowing covariance and contravariance helps developers manage the complexities of type variance in the ever-changing world of Java development. Adopting these ideas guarantees code that is resilient to changes in software development requirements and endures over time.

Youtube For Videos Join Our Youtube Channel: Join Now


Help Others, Please Share

facebook twitter pinterest

Learn Latest Tutorials


Trending Technologies

B.Tech / MCA