One of the more confusing aspects when learning to program with generics is determining when to use an upper bounded wildcard and when to use a lower bounded wildcard. This page provides some guidelines to follow when designing your code.
For purposes of this discussion, it is helpful to think of variables as providing one of two functions:
Of course, some variables are used both for "in" and "out" purposes — this scenario is also addressed in the guidelines.
You can use the "in" and "out" principle when deciding whether to use a wildcard and what type of wildcard is appropriate. The following list provides the guidelines to follow:
These guidelines do not apply to a method's return type. Using a wildcard as a return type should be avoided because it forces programmers using the code to deal with wildcards.
A list defined by List<? extends ...> can be informally thought of as read-only, but that is not a strict guarantee. Suppose you have the following two classes:
class NaturalNumber { private int i; public NaturalNumber(int i) { this.i = i; } // ... } class EvenNumber extends NaturalNumber { public EvenNumber(int i) { super(i); } // ... }
Consider the following code:
List<EvenNumber> le = new ArrayList<>(); List<? extends NaturalNumber> ln = le; ln.add(new NaturalNumber(35)); // compile-time error
Because List<EvenNumber> is a subtype of List<? extends NaturalNumber>, you can assign le to ln. But you cannot use ln to add a natural number to a list of even numbers. The following operations on the list are possible:
You can see that the list defined by List<? extends NaturalNumber> is not read-only in the strictest sense of the word, but you might think of it that way because you cannot store a new element or change an existing element in the list.