Covariance, Invariance, and Contravariance explained in plain English?
-
Covariance: Assign a subclass type to a superclass reference. A feature of java arrays because they are covariant:
-
Invariance: Types must match exactly: no subclass or superclass assignments are allowed. Java's generics are like a stubborn child, they are invariant.
-
Contravariance: Enabled in Java via wildcards (
<?>
). It helps the collection to hold a superclass of the stated type:
Simply put, covariance = more specific is OK, invariance = must be exact, contravariance = more generic is OK (using wildcards but not any wizard spells).
Covariance in method overriding:
From Java's 1.5 version onwards, covariance in method return types was possible when overriding. A method in superclass returning T
type can be overridden in subclass to return its subclass type too, thereby promoting code reusability and fluidity. It's like the baton pass in a relay race - smooth transition!
Generics and Invariance: A disciplined duo
Java Generics are designed to ensure type safety and abide by invariance. So, when dealing with collections, it's like the strict librarian preventing you from placing a horror book in the children's section - ensuring you don't add an incompatible object and create runtime errors.
Decoding Contravariance with generics:
Contravariance
could feel less intuitive but it's a matter of perspective—it deals more with receiving types than returning them. Thanks to wildcards like <?>
, Java achieves contravariance. A Consumer<? super T>
can gladly accept T
and any of its superclasses, just like an all-accepting, broad-minded philosopher.
Arrays and Variance: An interesting interaction:
While the covariant nature of Java arrays has its charm, it can lead to potential perils:
Using generic collections and maintaining invariance dodges this bullet efficiently.
Clearing the air: Addressing common misconceptions
Covariance
doesn't mean you can putPear
inApple
basket. Despite both being fruits,List<Pear>
is not a subtype ofList<Apple>
.Contravariance
with wildcards<? super T>
does not allow you to getT
type out of the collection without casting. After all, even loosen rules have fine prints.
Practical application in coffee, oh I mean code
- Covariance can come in handy when dealing with read-only data structures where a wider range of types being returnable is a good trait.
- Contravariance is like a secret ingredient, especially useful for functional interfaces, such as
Comparator<T>
, which lets a comparator for a type to be used with any subtypes.
Superhero crossover: Polymorphism and Type Variance
Superpowers of the Java's polymorphicsm and type variace are revealed when:
- Covariant return types strengthen the Liskov substitution principle, enabling more specialised types to be returned by methods in subclasses.
- Remind yourself that Invariance in generics doesn't allow a
List<Dog>
for aList<Animal>
, even thoughDog
is a good boi, I mean subtype ofAnimal
.
Was this article helpful?