Covariance and Invariance

About

Covariance and invariance are concepts in type systems that describe how types relate to each other in the context of inheritance or generic typing.

Covariance

Covariance allows a child type (Subclass) to be used where a parent type (Superclass) is expected. It maintains the "is-a" relationship.

Example: Covariance in Arrays

In Java, arrays are covariant. This means an array of a subtype can be assigned to an array of its supertype.

String[] strings = {"one", "two"};
Object[] objects = strings; // Allowed due to covariance

Potential Runtime Exceptions: While covariance allows this assignment, it is unsafe:

Object[] objects = strings;ava
objects[0] = 10; // ArrayStoreException at runtime

Why? At runtime, the JVM enforces that the array actually contains String elements.

Covariance in Generics

Generics in Java support covariance using wildcards (? extends T).

List<? extends Number> numbers = new ArrayList<Integer>();
  • ? extends Number means "a list of some subtype of Number".

  • We can read elements as Number, but we cannot add elements, as the exact subtype is unknown.

Invariance

Invariance means that a type and its subtypes are not interchangeable. This is stricter than covariance.

Example: Invariance in Generics

In Java, generic types are invariant. This means a List<String> is not a subtype of List<Object>, even though String is a subtype of Object.

List<String> strings = new ArrayList<>();
List<Object> objects = strings; // Compilation error: incompatible types

Why? If this were allowed, it would break type safety:

List<Object> objects = new ArrayList<String>();
objects.add(10); // Violates the type safety of `String` elements.

Comparison Table

Aspect

Covariant

Invariant

Definition

Subtypes can be used where supertypes are expected.

Types are not interchangeable, even with subtyping.

Example

String[] can be assigned to Object[].

List<String> cannot be assigned to List<Object>.

Flexibility

More flexible but less type-safe.

Stricter but safer.

Usage in Java

Arrays (T[]) are covariant.

Generics (List<T>) are invariant.

Last updated

Was this helpful?