What is ?
. Is it related to implementation details of the Java compiler or the type is defined in the JLS.
For instance,
public interface RecipientTypeVisitor<ReturnType> {
public ReturnType visit(RecipientSetType t);
}
public class RecipientSetType extends RecipientType{
public Integer accept(RecipientTypeVisitor<?> visitor){ //Error:
return visitor.visit(this); //Cannot convert capture of #1 to Integer
}
}
But if we write this:
public interface RecipientTypeVisitor<ReturnType> {
public ReturnType visit(RecipientSetType t);
}
public class RecipientSetType extends RecipientType{
public Object accept(RecipientTypeVisitor<?> visitor){ //Ok:
return visitor.visit(this); //this implies tha the capture of #1 is
//a subtype of Object as any refrence type in Java.
}
}
That's all I can say about a captured type
. So what is it actually?
The capture of a wildcard type is a type that is used by the compiler represent the type of a specific instance of the wildcard type, in one specific place.
Example: Take for example a method with two wildcard parameters, void m(Ex<?> e1, Ex<?> e2)
. The declared types of e1
and e2
are written exactly the same, Ex<?>
. But e1
and e2
could have different and incompatible runtime types.
The type checker must not consider the types equal even if they are written the same way. Therefore, during compilation the type parameters of e1
and e2
are given specific types, new ones for each place they are used. These new types are called the capture of their declared types.
The capture of a wildcard is an unknown, but normal and concrete type. It can be used the same way as other types.
A technical description of this can be found in the JLS:
5.1.10. Capture Conversion
Let G name a generic type declaration (§8.1.2, §9.1.2) with n type parameters A1,...,An with corresponding bounds U1,...,Un.
There exists a capture conversion from a parameterized type G (§4.5) to a parameterized type G, where, for 1 ≤ i ≤ n :
- If Ti is a wildcard type argument (§4.5.1) of the form ?, then Si is a fresh type variable whose upper bound is Ui[A1:=S1,...,An:=Sn] and whose lower bound is the null type (§4.1).
- ...
We can apply this to your example:
public Integer accept(RecipientTypeVisitor<?> visitor){ //Error:
return visitor.visit(this); //Cannot convert capture of #1 to Integer
}
A capture of the type parameter of RecipientTypeVisitor
is introduced during compilation. The captured type parameter is concrete but totally unknown (the JLS calls this a "fresh type variable"), and certainly not convertible to Integer
.
There is no way to denote the capture of a wildcard type directly, so you can't declare variables of that type or do much with it. You can however get a name for it indirectly by calling a generic method with it as a parameter. The JLS section I cited has a nice example of this further down:
public static void reverse(List<?> list) { rev(list); } private static <T> void rev(List<T> list) { List<T> tmp = new ArrayList<T>(list); for (int i = 0; i < list.size(); i++) { list.set(i, tmp.get(list.size() - i - 1)); } }
You have some choices :
public <T> T accept(RecipientTypeVisitor<T> visitor) {...}
this indicates your method uses some generics and links some of its components.
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