I've noticed JLS talks of 5.1.10 Capture Conversion, but I fail to understand what they are.
Can anyone explain them to me/give examples?
wildcard capture is the process of binding the value of a wildcard type to a new type variable.
In some cases, the compiler infers the type of a wildcard. For example, a list may be defined as List<?> but, when evaluating an expression, the compiler infers a particular type from the code. This scenario is known as wildcard capture.
Capture conversion was designed to make wildcards (in generics), ?
useful.
Suppose we have the following class:
public interface Test<T> {
public void shout(T whatever);
public T repeatPreviousShout();
}
and somewhere on our code we have,
public static void instantTest(Test<?> test) {
System.out.println(test.repeatPreviousShout());
}
Because test
is not a raw Test
and since repeatPreviousShout()
in "hindsight" returns a ?
, the compiler knows that there's a T
that serves as a type parameter for Test
.
This T
is for some unknown T
so the compiler erases the unknown type (for wildcard, it replaces with Object
)., hence repeatPreviousShout()
returns an Object
.
But if we had,
public static void instantTest2(Test<?> test) {
test.shout(test.repeatPreviousShout());
}
The compiler would give us an error of something like Test<capture#xxx of ?> cannot be applied
(where xxx
is a number, e.g. 337
).
This is because the compiler tries to do the type safety check on shout()
but since it received a wildcard, it doesn't know what T
represents, hence it creates a placeholder called capture of.
From here (Java theory and practice: Going wild with generics, Part 1), it clearly states:
Capture conversion is what allows the compiler to manufacture a placeholder type name for the captured wildcard, so that type inference can infer it to be that type.
Hope this helps you.
A parameterized type involving wildcard type arguments is really a union type. For example
List<? extends Number> = Union{ List<S> | S <: Number }
In 2 cases, instead of using List<? extends Number>
, Java uses the captured version List<S>
, where S is a just-created type variable with upper bound Number
.
(1) http://java.sun.com/docs/books/jls/third_edition/html/expressions.html
To narrow the type of an expression. If an expression's type is List<? extends Number>
, we know for sure that the runtime type of the object is actually a List<S>
for some concrete type S (S <: Number>
). So compiler uses List<S>
instead, to perform more accurate type analysis.
Capture conversion is applied to each expression individually; this leads to some dumb results:
<T> void test1(List<T> a){}
<T> void test2(List<T> a, List<T> b){}
List<?> x = ...;
test1(x); // ok
test2(x, x); // error
(2) http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.10.2
In subtype checking A :< B
where A
involves wildcard arguments. For example,
List<? extends Number> :< B
<=>
Union{ List<S> | S <: Number} :< B
<=>
List<S> :< B, for all S <: Number
So in effect, we are checking the captured version of type A
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With