Capture conversion is a process undergone by the compiler during type checking that effectively gives a unique, temporary name to a wildcard type that is not directly referencable by the developer, but can be used by the compiler to validate typing in certain operations. Capture conversion strengthens the applicability of wildcards.
Consistency information regarding wildcard types is not kept between two uses of the same wildcard type. For example, the fourth statement of the following code raises a compilation error:
List<String> strlist = new ArrayList<>();
strlist.add("some value");
List<?> myList = strlist;
myList.set(0, myList.get(0));
Despite it being obvious that execution of this code would never result
in type mismatches, (since the element returned by myList.get(0)
is of type String
, and myList
can
store strings), this code fails to compile due to type checking:
Because myList
's parameter type is a wildcard, ?
,
myList.get(0)
is ?
and
myList.set(...)
is
?
.
Java does not consider these two ?
wildcards as
equivalent, even though they represent the same type. In particular, a wildcard is not a named type, so two
distinct type references referring to the same wildcard are considered
unequal by the compiler. (This means that the compiler considers the
return type of myList.get
and the parameter of myList.set
as completely distinct types.)
Capture conversion helps to alleviate this issue.
Capture conversion is a process in which the compiler assigns an actual, inferred type to a wildcard, allowing code referencing the wildcard type to be used in certain contexts, like a method call:
<T> void doSomething(List<T> someList) {
// Works, because someList.get(0) is an expression of NAMED type T, which is equivalent to the type of the second parameter of someList.set(...)
// Java checks equality of named types.
someList.set(0, someList.get(0));
}
This method may be called with a List
whose type argument
is a wildcard:
List<?> myList = new ArrayList<>();
doSomething(myList); // Valid, despite being called with a list whose type is a wildcard.
In such a case as the method invocation doSomething(myList);
above, capture conversion is performed, replacing the wildcard type ?
in the type of the expression myList
with the actual type
Object
(see below
for detail on what the wildcard is replaced with during capture
conversion). The doSomething
method is then called with
the type parameter Object
, similar to as if by ContainingType.<Object>doSomething(myList);
.
Capture conversion is performed in certain, language-mandated contexts.
null
type, and If a type parameter, T extends
UpperBoundOne
is parameterized by ? extends
UpperBoundTwo
, the resulting new type has upper bound UpperBoundOne
& UpperBoundTwo
.
This allows for otherwise impossible casts in various cases. (See Cast Operator - Notes for examples.)