Nested wildcards
It is important to understand the implication of the wildcard types.
You already understood that you can assign your Map<Integer, Map<Integer, String>>
to Map<?, ?>
as Map<?, ?>
implies arbitrary types, unknown to whoever might have a reference of the declared type Map<?, ?>
. So you can assign any map to Map<?, ?>
.
In contrast, if you have a Map<?, Map<?, ?>>
it has an unknown key type but the value type is not unknown. It’s Map<?,?>
the type, recall the information above, that can be assigned with any map.
So, the following code is legal:
Map<?, Map<?, ?>> map=new HashMap<>();
map.put(null, Collections.<String,String>singletonMap("foo", "bar"));
map.put(null, Collections.<Double,Integer>singletonMap(42.0, 1000));
map.put(null, Collections.<Object,Boolean>singletonMap(false, true));
Here, we are putting a null
key as we can’t put
anything else for keys but arbitrary typed maps as values as that’s what a value type of Map<?, ?>
implies: can be assigned from arbitrary maps. Note that by iterating over the entries we can also set other entries having non-null
keys to arbitrary maps then.
So I’m quite sure that you don’t want to assign your Map<Integer, Map<Integer, String>>
to a Map<?, Map<?, ?>>
and discover arbitrary maps not being Map<Integer, String>
as values afterwards and that you are quite happy that the compiler doesn’t allow this.
What you actually want to do is to assign your map to a type which has both, key and value type, unknown but still telling that your values are maps:
Map<Integer, Map<Integer, String>> someMap = new HashMap<>();
Map<?, ? extends Map<?, ?>> map=someMap;
In the generic type system Map<Integer, String>
is a sub-type of Map<?, ?>
so you can assign it to Map<?, ?>
as well as ? extends Map<?, ?>
. This sub-type relationship is not different than the relationship of String
to Object
. You can assign any String
to a variable of type Object
but if you have a Map<?,String>
you can’t assign it to Map<?,Object>
but only to Map<?, ? extends Object>
for the same reason: the map shall continue to contain String
s as values rather than receiving arbitrary objects.
Note that you can workaround this limitation. You can say:
Map<Integer, Map<Integer, String>> someMap = new HashMap<>();
Map<?, Map<?, ?>> map=Collections.unmodifiableMap(someMap);
Since the map returned by unmodifiableMap
does not allow any modifications, it allows widening the key and value types. The contained values are of the specified type (i.e. Map<?, ?>
) when you query the map, but attempts to put in arbitrary map values, while not rejected by the compiler, will be rejected at runtime.
Java generics, nested collection of wildcard
Because it would break type safety:
List<List<Object>> lo = new ArrayList<List<Object>>();
List<List<? extends Object>> ll = lo;
List<String> ls = new ArrayList<String>();
ll.add(ls);
lo.get(0).add(new Object());
String s = ls.get(0); // assigns a plain Object instance to a String reference
Double wildcard parameterization (nested wildcards) with Java generics
Use the following instead:
Set<? extends Class<?>> subTypes = reflections.getSubTypesOf(type);
The problem is that nested wildcards don't perform type capture. Declaring a Set<Class<?>>
means "a set of classes of any type", while what's being returned is a Set<Class<? extends capture#19-of ?>>
, which means "a set of classes of any type extending from some specific unknown type". In this case, that "specific unknown type" is derived from the type argument to T
, which is inferred from type
to be an unbounded wildcard capture (the ?
in Class<?>
).
For example, pretend that "specific unknown type" is Number
:
Class<Number> type = ...
Set<Class<?>> subTypes = reflections.getSubTypesOf(type);
Here, getSubTypesOf
returns a Set<Class<? extends Number>>
. That type is not assignable to Set<Class<?>>
because generic types aren't covariant. But, wildcard capture helps us express covariance, allowing types like Set<? extends Class<?>>
. The caveat is that we can't add anything but null
to such a set, since we don't know its specific type.
Related posts:
- Java Generic List<List<? extends Number>>
- Multiple wildcards on a generic methods makes Java compiler (and me!) very confused
- What is PECS (Producer Extends Consumer Super)?
Similar posts:
- Java: Wildcard Types Mismatch Results in Compilation Error
- Issue with declaration of Map<String,Class<? extends Serializable>>
- Bounded-wildcard related compiler error
Nested generics and wildcards
?
means "unknown type". Since the type is unknown, the compiler can't guarantee that the type is Map<String, String>
. So it refuses to let you add anything in the queue, since it could compromise its type-safety.
Your variable should be declared as
Queue<Map<String, String>> q = new LinkedList<Map<String, String>>();
or simply, if you're on Java 7 or later
Queue<Map<String, String>> q = new LinkedList<>();
Mixing nested type parameters and wildcards in Java
The reason is that the ?
in List<?>
could be "anything", but a different "anything" in each Map
entry. That is, it would accept a List<String>
in one entry, and a List<Integer>
in another.
But you are passing in a Map
that has the same type of List
in every entry, so the type is not bound in the same way or the to same degree for freedom.
The "fix" is to lock the type to a specific type, but still being "anything" - just the same "anything* in every entry, by typing the method:
public static <T> void accept(Map<String, List<T>> multiMap) // complies
or if your method really doesn't need to know which type, use a wildcard to wrap the type:
public static void accept(Map<String, ? extends List<?>> multiMap) // compiles
This last version works because the type of the list, although being a wildcard, is fixed to an unknown, but consistent, type when called.
I find the typed version easier to read (and code), and the type is there for use should you decide later that your method needs to know the type.
Terms aggregation with nested wildcard path
Tdlr;
A bit late to the party.
I would suggest a different approach as I don't see a possible solution using wildcards.
My solution would involve using the copy_to
to create a field that you will be able to access using aggregation.
Solution
The idea is to create a field that will store the values of all your classifiers.
Which you can be doing aggregation on.
PUT /54198251/
{
"mappings": {
"properties": {
"classifiers": {
"type": "keyword"
},
"parent": {
"type": "nested",
"properties": {
"child": {
"type": "nested",
"properties": {
"classifier": {
"type": "keyword",
"copy_to": "classifiers"
}
}
},
"child2": {
"type": "nested",
"properties": {
"classifier": {
"type": "keyword",
"copy_to": "classifiers"
}
}
}
}
}
}
}
}
POST /54198251/_doc
{
"parent": {
"child": {
"classifier": "c1"
},
"child2": {
"classifier": "c2"
}
}
}
GET /54198251/_search
{
"aggs": {
"classifiers": {
"terms": {
"field": "classifiers",
"size": 10
}
}
}
}
Will give you:
"aggregations": {
"classifiers": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "c1",
"doc_count": 1
},
{
"key": "c2",
"doc_count": 1
}
]
}
}
Wild card ? extends T throws incompatible types error for non-static nested class
The problem is that the compiler doesn't know that the type of LinkedList<? extends T>
is the same type as Node<? extends T>
- the two wildcard types could be different subtypes of T
, so the compile error is appropriate.
The fix is to type the method, locking the subtype to the same subtype for both:
public <U extends T> void concat(LinkedList<U> otherList) {
// see below
}
This is the same as a wildcard <? extends T>
, but it's a constant for the method invocation.
You need a little more generics fu inside the method too:
public <U extends T> void concat(LinkedList<U> otherList) {
// Because you have an inner class, you must use this syntax
LinkedList<U>.Node<U> otherListHead = otherList.head;
// Create the local typed Node using the foreign Node's data
Node<T> node = new Node<>(otherList.head.item);
// Add node to this and repeat for all Nodes in the other list
}
The reason it works without special syntax when Node is a static class, ie:
public <U extends T> void concat(LinkedList<U> otherList) {
Node<U> otherListHead = otherList.head; // doesn't need LinkedList<U> prefix
// ...
}
is because whereas instances of static classes exist independently, inner classes can't exist without the enclosing class instance and this is just the syntax that java requires.
Incidentally, when the Node class is not static, the type T
of Node is hiding the type T
of LinkedList, so you should delete the type from Node, instead just using the type T
from LinkedList which the inner class Node acquires from the enclosing LinkedList instance, ie:
public static class LinkedList<T> {
Node head;
private class Node { // non static version should not be typed
T item; // T comes from the enclosing class instance
Node next;
Node(T item){
this.item = item;
}
}
// ...
}
Perhaps that is what you intended.
Related Topics
Does Java Guarantee That Object.Getclass() == Object.Getclass()
Hibernate/JPA - Annotating Bean Methods VS Fields
Modifier Static Is Only Allowed in Constant Variable Declarations
Howto Extract Mimetype from a Byte[]
How to Write and Read Java Serialized Objects into a File
How to Determine the Ip of My Router/Gateway in Java
Jsp Generating Excel Spreadsheet (Xls) to Download
Why Is Super Class Constructor Always Called
Why Is the Tostring() Method Being Called When I Print an Object
Printf %F with Only 2 Numbers After the Decimal Point
Why Can't You Reduce the Visibility of a Method in a Java Subclass
Differencebetween Reader and Inputstream
Difference Between "This" And"Super" Keywords in Java
Changing Java Platform on Which Netbeans Runs
How to Enable Wire Logging for a Java Httpurlconnection Traffic