In this section, we’ll consider some of the more advanced uses of wildcards. We’ve
seen several examples where bounded wildcards were useful when reading from a data
structure. Now consider the inverse, a write-only data structure.
The interface Sink is a simple example of this sort.
interface Sink<T> {
flush(T t);
}
We can imagine using it as demonstrated by the code below. The method writeAll()
is designed to flush all elements of the collection coll to the sink snk, and return the
last element flushed.
public static <T> T writeAll(Collection<T> coll, Sink<T> snk) {
T last;
for (T t : coll) {
last = t;
snk.flush(last);
}
return last;
}
...
Sink<Object> s;
Collection<String> cs;
String str = writeAll(cs, s); // illegal call
As written, the call to writeAll() is illegal, as no valid type argument can be inferred;
neither String nor Object are appropriate types for T, because the Collection element
and the Sink element must be of the same type.
We can fix this by modifying the signature of writeAll() as shown below, using a
wildcard.
public static <T> T writeAll(Collection<? extends T>, Sink<T>) {
...
}
...
String str = writeAll(cs, s); // call ok, but wrong return type
The call is now legal, but the assignment is erroneous, since the return type inferred
is Object because T matches the element type of s, which is Object.
The solution is to use a form of bounded wildcard we haven’t seen yet: wildcards
with a lower bound. The syntax ? super T denotes an unknown type that is a
supertype of T3. It is the dual of the bounded wildcards we’ve been using, where we
use ? extends T to denote an unknown type that is a subtype of T.
public static <T> T writeAll(Collection<T> coll, Sink<? super T> snk) {
...
}
...
String str = writeAll(cs, s); // Yes!
Using this syntax, the call is legal, and the inferred type is String, as desired.
and i can see that the <T> used by the Type or method describes the identical T usage within its domain.