Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a capture conversion in Java and can anyone give me examples?

Tags:

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?

like image 492
John Assymptoth Avatar asked Dec 13 '10 17:12

John Assymptoth


People also ask

What is capture in Java?

wildcard capture is the process of binding the value of a wildcard type to a new type variable.

What is wildcard capture Java?

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.


2 Answers

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.

like image 108
Buhake Sindi Avatar answered Sep 25 '22 20:09

Buhake Sindi


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

like image 21
irreputable Avatar answered Sep 21 '22 20:09

irreputable