Java Generics — Covariance and Contravariance
Since Java 1.5 when the Generics was introduced, the Java developer life changed a lot, and changed in a good way.
In this article will handle Covariance(? extends T) and Contravariance(? super T) and will be splitted into definition, example, and conclusion.
1. Definition
1.1. Covariance
Using the covariance is allowed to use any subtype of FirstClass, such as Suite and Superior instances.
List<? extends T>
// or in the example
List<? extends FirstClass>
1.2. Contravariance
Use elements defined to use in the declaration of its supertypes.
List<? super T>
// or in the example
List<? super Gourmet>
All super classes based on Gourmet are supported. Because of this, a list of Degustacion is not supported.
List<Gourmet> gourmets = Collections.singletonList(Gourmet.INSTANCE); //OK
List<Degustacion> degustacions = Collections.singletonList(Degustacion.INSTANCE); // NOT SUPPORTEDvoid contravarianceForTheSecondType(List<? super U> items)...
2. Example
To explain this Java feature, the use case will be based on flights. The flight has sections to seat (First and Second classes), and food to be served (Gourmet, Degustación, Fast..etc).
The point to achieve here is to give an idea about covariance and contravariance, not model a perfect scenario about flights.
Check below the class diagram.
3. Classes
All classes are available on my GitHub.
4. Stack
- OpenJDK 11
- Maven 3
5. Conclusion
Either to guarantee some business logic or to enforce the correct type, it’s clear the benefits of Generics and should be used instead of manually controls even though sometimes is really required.