-
Notifications
You must be signed in to change notification settings - Fork 8
Wildcards
Wildcards belong to peculiar sort of types — existential types. They can not be instantiated directly, because their concrete type is by definition not known. They don't mix well with normal Java types, instead their relationships with each other and normal "classy" types are guided by concepts of containment 1 and capture 2. Containment (not subtyping!) is what makes assignment between wild-carded types possible:
List<? extends Parcelable> exampleList = new ArrayList<RectF>();
Note, that ? extends Parcelable
and RectF
aren't connected by subtyping relationships and can not be assigned
to each other (there is no conversion route). Yet, two Lists above are assignable thanks to containment relationships between
their type arguments.
Wait, but how is it even possible to call methods such as List#get()
, if there is no conversion route!?
Parcelable exampleListMember = exampleList.get();
The return type of #get()
in above example is undoubtedly ? extends Parcelable
— a type, which can be neither instantiated, nor
assigned to any other type in language. How do we assign it to Parcelable
? This is where capture conversion comes to play.
Every time, when you call a method of type, parametrized with wildcards, a capture conversion will automatically kick in and "capture" all types within the method signature. This results in creation of temporary invisible type variable 3 for each wildcard with upper/lower bounds based on originating wildcard.
Unlike wildcards, type variables have well-defined identity, which allows them to be used during type inference. The can be used in various contexts including being assigned to/from other types, thanks to their upper bound being their direct supertype (which is not true for wildcards).
The curious nature of existential types and capture conversion allows for various silly tricks. For example, the following List
is effectively immutable, because the parameter of #add(E)
can not accept anything, not even Object:
List<? extends String>
This amazing flexibility and convenience of use have made creators of Generic Java project totally love the wildcards, the love and adoration to which are being shared to this day by every Java programmer 4.
1: https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.5.1 ↩
2: https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.10 ↩
3: Also referred to as "fresh type variable" ↩
4: At least, that's how it was supposed to work in theory… ↩