Reputation: 27385
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?
Upvotes: 4
Views: 2946
Reputation: 529
You have some choices :
public <T> T accept(RecipientTypeVisitor<T> visitor) {...}
this indicates your method uses some generics and links some of its components.
Upvotes: 3
Reputation: 12112
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)); } }
Upvotes: 3
Reputation: 19682
(This is from another answer of mine, but it is more suitable for this question, explaning wildcard itself)
A wildcard ?
is not a type. It is a type argument. The syntax though is very deceiving (by design).
Let's use a different syntax - if there's any 1st-level wildcard, use {}
instead of <>
, e.g.
List{?}, Map{String, ? extends Number}
The meaning of {?}
is to declare a union type
List{? extends Number} == union of List<Number>, List<Integer>, List<Long>, ....
It's easy to see that, List<Integer>
is a subtype of List{? extends Number}
; and
List{? extends Number}
is a subtype of List{? extends Object}
In our syntax, <>
is reserved for substituting type vars with types. So we write
List<String>
, etc. It's easy to understand their meaning - just replace T
's with String
in the source code of List
, we get a good-old plain class.
interface List<String>
String get(int)
This cannot be done for wildcard - it makes no sense
interface List<?>
? get(int)
So it is not allowed to new ArrayList{?}()
, or class MyList implements List{?}
So, how can we use List{?}
? What methods we can call on it?
When the type of an expression is a List{?}
, we know that it is an object, and the object must belong to a subclass of List<x>
for some unknown type x
. This is wildcard capture
obj is a List{?} => obj is a List<x>, where x a subtype of Object.
Even though the exact type of x
is unknown at compile time, we can still do the substitution
interface List<x>
x get(int)
so we can make sense of the call obj.get(0)
; it returns x
, and x
is a subtype of Object
; so we can assign the return value to an Object
.
Upvotes: 2
Reputation: 2922
The char ?
is a wildcard meaning you don't know the type. its doesn't mean its type is Object
its by definition undefined
but in Java you can hold any type of object in Object
type.
ArrayList<?> list1 = new Arraylist<?>(); // list of undefined objects
You cannot add objects in list1, but after casting you can.
ArrayList<Object> list2 = new Arraylist<Object>(); // list of objects of type Object
You can add objects in list2 of any type
Upvotes: 1
Reputation: 2878
Every class extends from Object so the typecast from ?
to Object
is safe.
To get the same with Integer
you can use RecipientTypeVisitor<? extends Integer>
but since Integer is a final class that is useless, Integer
cannot be subclassed. It is equivalent to RecipientTypeVisitor<Integer>
.
Why do you want this?
You can check the official tutorial here.
The most important thing to know:
In generic code, the question mark (?), called the wildcard, represents an unknown type.
(...)
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.
For the most part, you don't need to worry about wildcard capture, except when you see an error message that contains the phrase "capture of".
Upvotes: 1