Generics in Java and especially such with upper and lower bounds can be confusing even though they are otherwise very useful.

Here is an example which explains it all well:

import java.util.ArrayList;
import java.util.List;

class A {
}

class B extends A {
}

public class Test {
	public static void main(String[] args) {
		// First example with upper bound A
		List<? extends A> list1 = new ArrayList<A>();
		List<? extends A> list2 = new ArrayList<B>();
		// List<? extends A> list3 = new ArrayList<Object>(); won't compile

		// Second example with lower bound A
		List<? super A> list5 = new ArrayList<A>();
		List<? super A> list6 = new ArrayList<Object>();
		// List<? super A> list5 = new ArrayList<B>(); // won't compile
	}
}

We have two classes - A and B. B extends A. We'll use them to test the upper and lower bounds of the wildcard generics in a class called Test with a List object.

To simplify it in short:

  • Upper bound is a boundary that includes the specified class or any which it extends.
  • Lower bound includes the specified class or any super class to it.

In the first example:

List<? extends A> list1 = new ArrayList<A>();
List<? extends A> list2 = new ArrayList<B>();
// List<? extends A> list3 = new ArrayList<Object>(); won't compile

When the wildcard extends A this means that the accepted objects will be either A or B. B is accepted because it extends A. Object will not be accepted because it doesn't extend A.

In the second example:

List<? super A> list5 = new ArrayList<A>();
List<? super A> list6 = new ArrayList<Object>();
// List<? super A> list5 = new ArrayList<B>(); // won't compile

The wildcard (?) is linked with the keyword super A, this means that classes A or super classes of A (such as Object) will be accepted. However, B is not accepted because it is not a super class to A.