Please show a good example for covariance and contravariance in Java.
3 Answers
Covariance:
class Super {
Object getSomething(){}
}
class Sub extends Super {
String getSomething() {}
}
Sub#getSomething is covariant because it returns a subclass of the return type of Super#getSomething (but fullfills the contract of Super.getSomething())
Contravariance
class Super{
void doSomething(String parameter)
}
class Sub extends Super{
void doSomething(Object parameter)
}
Sub#doSomething is contravariant because it takes a parameter of a superclass of the parameter of Super#doSomething (but, again, fullfills the contract of Super#doSomething)
Notice: this example doesn't work in Java. The Java compiler would overload and not override the doSomething()-Method. Other languages do support this style of contravariance.
Generics
This is also possible for Generics:
List<String> aList...
List<? extends Object> covariantList = aList;
List<? super String> contravariantList = aList;
You can now access all methods of covariantList
that doesn't take a generic parameter (as it must be something "extends Object"), but getters will work fine (as the returned object will always be of type "Object")
The opposite is true for contravariantList
: You can access all methods with generic parameters (you know it must be a superclass of "String", so you can always pass one), but no getters (The returned type may be of any other supertype of String)

- 6,476
- 2
- 22
- 20
-
81The first example of contravariance doesn't work in Java. doSomething() in the Sub class is an overload, not an override. – Craig P. Motlin Apr 14 '11 at 22:26
-
16Indeed. Java does not support contravariant arguments in subtyping. Only covariance for what concern method return types (like in the first example). – the_dark_destructor Feb 16 '12 at 17:51
-
Great answer. Covariance looks logical to me. But could you point me a paragraph in JLS which describes contravariance? Why Sub.doSomething is invoked? – Mikhail Apr 08 '13 at 08:37
-
3As Craig pointed out, it isn't. I think here is a clash between overriding and overloading and SUN did choose (as always) the backward-compatible option. So in Java you can't use contravariant parameters when overriding a method. – Hardcoded Apr 25 '13 at 14:47
Co-variance: Iterable and Iterator. It almost always makes sense to define a co-variant Iterable
or Iterator
. Iterator<? extends T>
can be used just as Iterator<T>
- the only place where the type parameter appears is the return type from the next
method, so it can be safely up-cast to T
. But if you have S
extends T
, you can also assign Iterator<S>
to a variable of type Iterator<? extends T>
. For example if you are defining a find method:
boolean find(Iterable<Object> where, Object what)
you won't be able to call it with List<Integer>
and 5
, so it's better defined as
boolean find(Iterable<?> where, Object what)
Contra-variance: Comparator. It almost always makes sense to use Comparator<? super T>
, because it can be used just as Comparator<T>
. The type parameter appears only as the compare
method parameter type, so T
can be safely passed to it. For example if you have a DateComparator implements Comparator<java.util.Date> { ... }
and you want to sort a List<java.sql.Date>
with that comparator (java.sql.Date
is a sub-class of java.util.Date
), you can do with:
<T> void sort(List<T> what, Comparator<? super T> how)
but not with
<T> void sort(List<T> what, Comparator<T> how)
Look at the Liskov substitution principle. In effect, if class B extends class A then you should be able to use a B whenever an A is required.

- 23,575
- 2
- 47
- 51
-
8This isn't answering the question and is misleading. It would be entirely possible to design a variant system that breaks semantic correctness and therefore violates LSP. – Matt Whipple Sep 23 '16 at 12:26
-
1this isn't the case for `contra variant` say. `super.doSomething("String")` could not be replaced by `sub.doSomething(Object)`. – zinking Jan 26 '17 at 10:07
-
1