Index


Overview


Java has strict type restrictions (will talk about "invariant" in a moment). In some cases we need to widen these restrictions. The wildcard operator allows us to do that.

A Few Terms


A few terms we run into are invariant, covariant, and contravariant.

To establish a baseline, let's start off with the mathematical defintions:


In coding, we are often concerned with how types translate. For example, in this example we assign a String to a variable of type Object. In other words we assign a more specific object to a more general variable. It is allowed.
Object o;
o = "I am a String";
From our previous successful snippet, we might assume we can make the assignment shown here (to the "objects" var). However, Java does not allow it, giving us an error such as:
incompatible types: List<String> cannot be converted to List<Object>.


Why?
The following snippet will show us.
List<Object> objects;
List<String> strings = new ArrayList<>();
objects = strings;
The list is read-write meaning elements can be added to it. So Java thinks that if we're allowed to assign "strings" to "objects", we may try to add an improper type as shown (e.g. an Integer into a List of String subtypes).

This is the reason for the "incompatible types..." error.
List<Object> objects;
List<String> strings = new ArrayList<>();
objects = strings;
objects.add(10);
But what if we have a method that uses the list in a "read-only" way (like "preintList" here). This looks like it should work.

Java does not allow it (for reasons we just discussed). The method parm is "invariant" (restricted).

The next snippet will show us how we can widen the type restriction.
public void printList(List<Object> list) {
	for (Object o: list)
		prn(o.toString());
}

public void caller() {
	List<String> names =
		Arrays.asList("A", "B", "C", "D");
	printList(names);
}
By adding the generic wildcard "? extends Object", Java allows it. Any subtype that extends Object is allowed. This parameter is now "covariant" per the wildcard (any list subtype that extends "Object" is allowed).
public void printList(List<? extends Object> list) {
	for (Object o: list)
		prn(o.toString());
}
public void caller() {
	List<String> names =
		Arrays.asList("A", "B", "C", "D");
	printList(names);
}

Here is an example of covariant return type where a more specialized return type is allowed.
//in superclass
public Object foo() {
	//...

//in subclass
public String foo()
	//...

Contravariant And Comparator


Contravariance is not used as much as covariance.

However, we might see it used for Comparator. Like this:
Comparator<? super T>


See more here...

References