Sobes.tech
Senior

Tell me what generics are in Java and what are the differences between invariance, covariance, and contravariance when using them?

sobes.tech AI

Answer from AI

Generics in Java allow creating classes, interfaces, and methods with type parameters, ensuring type safety and code reusability without the need for casts.

Invariance means that the type parameter must exactly match. For example, List<String> is not a subtype of List<Object>.

Covariance allows using a more specific type than expected. In Java, this is implemented through wildcards with extends: List<? extends Number> — you can read elements as Number, but cannot add.

Contravariance — on the contrary, allows using a more general type. In Java, this is a wildcard with super: List<? super Integer> — you can add Integer and its subtypes, but when reading, you get Object.

Example:

List<? extends Number> numsCovariant = new ArrayList<Integer>();
Number n = numsCovariant.get(0); // reading is allowed
// numsCovariant.add(10); // compilation error

List<? super Integer> numsContravariant = new ArrayList<Number>();
numsContravariant.add(10); // adding is allowed
Object obj = numsContravariant.get(0); // reading returns Object

Thus, covariance is convenient for reading, contravariance — for writing.