[3] Since the reference literal null has no type, the type-system will allow you to invoke add
passing null, but this is an uninteresting boundary case with little practical significance.
SingleLinkQueue<?> strings =
new SingleLinkQueue
strings.add("Hello"); // INVALID: won't compile
SingleLinkQueue<? extends Number> numbers =
new SingleLinkQueue
numbers.add(Integer.valueOf(25)); // INVALID: won't compile
This is a reasonable restriction because in general, if passed a queue of an unknown kind, you have no idea
what type of object you can store in it. So you can't store a String (or an Object or a Number or ...) in a
queue that could require some other kind of element. Nor can you store a Number in a queue in which the
elements are known to be Number objects or objects of a subclass of Numberbecause in the subclass case
passing a general Number object would be incorrect. However, given strings above, you could invoke
remove and assign the result to an Object referencebecause the returned value must be compatible with
Object. Similarly, given numbers, you could invoke remove and assign the result to a Number
referencebecause the returned value must be at least a Number.
In contrast, given a lower-bounded wildcard type, the wildcard is known to be the same as, or a super type of,
the bound, so adding an element of the same type as the bound is always correct. For example, this method is
perfectly correct:
static void addString(SingleLinkQueue<? super String> sq) {
sq.add("Hello");
}
No matter what queue is passed to addString, you're guaranteed that it can hold String objects.
Wildcards can be used in most declarations: fields, local variables, parameter types, and return types. But you
can't use them to name a class or interface in an extends or implements clause. Any parameterized types
that a class (or interface) extends or implements must be concrete types in which the immediate type argument
is not a wildcard. For example, you can't define a class that implements List<?>. However, the type
argument may itself be a parameterized type with a type argument that is a wildcard so implementing
List<List<?>> is okay.
You'll see more examples of the use of wildcards when we look at the collection classes in detail in Chapter
21.
11.3. Generic Methods and Constructors
Earlier we mentioned how the SingleLinkQueue class might want to expose the elements of the queue as
an array. We noted then that it was impossible to create an array with the type variable E and that instead the
caller should pass in an array of the right size and type. Here's a first attempt at defining such a method:
public E[] toArray_v1(E[] arr) { // too restrictive!
int i = 0;
for (Cell
c != null && i < arr.length;
c = c.getNext())
arr[i++] = c.getElement();