I am reading multi-level wild cards from AngelikaLangerGenericsFaq. I am pretty confused about the syntax. The document says
The type
Can someone elaborate on these three quotes with example. I am totally lost into the syntax
Well, it wouldn't make sense to write those 3 quotes again here, as I can't give a better explanation than that. Instead, I will try to answer your other questions below, then possibly you will understand the answer to this one too. If not, you can ask your query again and I'll try to elaborate a little further.
Document says, para-1 is the concrete instantiation of a generic type and other is not the concrete instantiation? How is that?
A concrete instantiation is the one in which all the type arguments are concrete types, and are known at compile time. For e.g., List<String>
is a concrete instantiation, because String
is a concrete type. Its type is known at compile time. Whereas, List<? extends Number>
is not a concrete type, because ? extends Number
can be any type that extends Number
. So, its type is unknown at compile time. Similarly, Map<String, Integer>
is a concrete instantiation of generic type Map<K, V>
.
In the case of multi-level type parameters, List<List<? extends Number>>
, the outer List
is a concrete instantiation of List<E>
, because the type of elements is known to be a List
at compile time, although the inner List
is a wildcard instantiation, as the type of elements stored can be Integer
, Double
, any subclass of Number
. But that paragraph is talking about the outer type only. And the outer type can only contain List
type.
That's why the first paragraph said, it's a heterogenous collection of Pair
, because the actual type parameter of Pair
can be anything, but that is certain to be Pair
and nothing else.
What does it mean to read the wild-cards top down?
Talking in layman's term, it means from left-to-right. While determining the type of the parameterized type, you first see the outermost type parameter. Then if that type parameter is itself a parameterized type, then you move onto the type parameters of that parameterized type. So, we read the type parameters, from left-to-right.
What is the advantage of multi-level wild cards?
Suppose you want to create a List of List of Fruits. Now your inner List
can contain any kind of of fruits. An apple is also a fruit, and a banana is also a fruit. So, you have to make sure that you get all of them. Now, since generic types are invariant, in the sense, List<Apple>
is not the same as List<Fruit>
, you can't add a List<Apple>
if your type of list is List<List<Fruit>>
. For that you would need to use wildcards
like this - List<List<? extends Fruit>>
, which can now take List<Apple>
, List<Banana>
, list of any fruit.
Generic types with wildcards are really "existential" types. If you're familiar at all with logic, you can read G< ? extends T >
as ∃S extends T:G< S >
.
Angela's explanation about reading types "top down" really means that the imaginary existential quantifier implied by a type that contains a ?
in it is always as close as possible to the ?
. For example, you should mentally rewrite G< H< ? extends T > >
to G<
∃S extends T:H< S > >
. Since there's no quantifier on the outside, it's called concrete.