Can't cast to to unspecific nested type with generics
Use the following:
Msg<? extends Value<?>> someMsg = strMsg;
The problem is that the ?
in Msg<Value<?>> objMsg
is NOT capable of capture conversion. It's not "a Msg
of Value
of some type. It's "a Msg
of Value
of ANY type".
This also explains why along with the declaration change, I've also renamed the variable to someMsg
. The Value
can't just be any Object
. It must belong to some type (String
in this example).
A more generic example
Let's consider a more generic example of a List<List<?>>
. Analogously to the original scenario, a List<List<?>>
can NOT capture-convert a List<List<Integer>>
.
List<List<Integer>> lolInt = null;
List<List<?>> lolAnything = lolInt; // DOES NOT COMPILE!!!
// a list of "lists of anything"
List<? extends List<?>> lolSomething = lolInt; // compiles fine!
// a list of "lists of something"
Here's another way to look at it:
- Java generics is type invariant
- There's a conversion from
Integer
toNumber
, but aList<
Integer
>
is not aList<
Number
>
- Similarly, a
List<Integer>
can be capture-converted by aList<?>
, but aList<
List<Integer>
>
is not aList<
List<?>
>
- Similarly, a
- Using bounded wildcard, a
List<? extends
Number
>
can capture-convert aList<
Integer
>
- Similarly, a
List<? extends
List<?>
>
can capture-convert aList<
List<Integer>
>
- Similarly, a
The fact that some ?
can capture and others can't also explains the following snippet:
List<List<?>> lolAnything = new ArrayList<List<?>>(); // compiles fine!
List<?> listSomething = new ArrayList<?>(); // DOES NOT COMPILE!!!
// cannot instantiate wildcard type with new!
Related questions
- Multiple wildcards on a generic methods makes Java compiler (and me!) very confused
- Very long and detailed exploration into this problem
- Java Generic
List<List<? extends Number>>
- Any simple way to explain why I cannot do
List<Animal> animals = new ArrayList<Dog>()
? - What is the difference between
<E extends Number>
and<Number>
?
See also
- Java Generics Tutorial
- Generics and Subtyping | Wildcards | More Fun with Wildcards
- Angelika Langer's Java Generics FAQ
- What is a bounded wildcard?
- Which super-subtype relationships exist among instantiations of generic types?
Calling java method with Set with nested ? generic type
Nested wildcards can cause some unexpected incompatibilities. Try this:
public String buildMessageForViolations(Set<? extends ConstraintViolation<?>> constraintViolations) {
multiple nested wildcard - arguments not applicable
The following compiles as expected:
List<Set<? extends Set<?>>> list = new ArrayList<Set<? extends Set<?>>>();
list.add(new HashSet<Set<String>>());
list.add(new HashSet<Set<Integer>>());
The problem is that generics is type invariant.
Consider the simpler example:
- Given that there is a casting conversion from
Animal
toDog
(e.g.Dog extends Animal
)...- A
List<Animal>
IS NOT aList<Dog>
- A
- There is a capture conversion from
List<? extends Animal>
to aList<Dog>
Now here's what happens in this scenario:
- Given that there is a capture conversion from
Set<?>
toSet<String>
...- A
Set<Set<?>>
IS NOT aSet<Set<String>>
- A
- There is a capture conversion from
Set<? extends Set<?>>
toSet<Set<String>>
So if you want a List<T>
where you can add a Set<Set<String>>
, Set<Set<Integer>>
, etc, then T
is NOT Set<Set<?>>
, but rather Set<? extends Set<?>>
.
Related questions
- Can't cast to to unspecific nested type with generics
- Multiple wildcards on a generic methods makes Java compiler (and me!) very confused
- Java Generic
List<List<? extends Number>>
- Any simple way to explain why I cannot do
List<Animal> animals = new ArrayList<Dog>()
? - What is the difference between
<E extends Number>
and<Number>
?
See also
- Java Generics Tutorial
- Generics and Subtyping | Wildcards | More Fun with Wildcards
- Angelika Langer's Java Generics FAQ
- What is a bounded wildcard?
- Which super-subtype relationships exist among instantiations of generic types?
Java generics incompatible types compilation error for generic static method call in Oracle Java SE 8u20 JDK
Anything between <
& >
is type invariant unless you use a ?
wildcard.
The types of Set<? extends Object>
& Set<Object>
are different, and therefore need type variance to be considered compatible.
If they're at the top level, as for works1
, the top-level Set
is outside the <
& >
, so the normal Java type variance works, but for fails1
, they're inside the <
& >
, so the types are invariant.
Type variance can be enabled within the <
& >
by changing the outermost part of the type declaration from Set<Set<...>>
Set<? extends Set<...>>
.
Thus, the following code compiles correctly:
Set<? extends Set<? extends Object>> works4 = Collections.<Set<Object>>emptySet();
I derived my answer from the answer to the following question (which was mentioned above by @MarkoTopolnik):
multiple nested wildcard - arguments not applicable
The answer to the following question provided a more detailed explanation:
Can't cast to to unspecific nested type with generics
Why is this conversion not valid?
It's not valid because if it was valid you'd be able to add non-integer lists to ml
as well.
Example (not valid):
Map<String, List<Integer>> ml;
Map<String, List<?>> ml3 = ml;
ml3.put("strings", Arrays.asList("evil","string"));
List<Integer> l = ml.get("strings"); //see how this is going to fail?
Why is Map<String, ?> ml2 = ml;
valid? That's because the use of a wildcard tells the compiler to not allow adding new elements, i.e. ml2.put("strings", Arrays.asList("evil","string"));
would not be allowed (the compiler doesn't do a type check, it just sees the wildcard and knows you must not call that method.
Compilation failure calling method with nested wildcard
You should change your methods to the following:
private static <T, U extends Collection<?>> Stream<T> getStreamOfMappingToN(Map<T, U> map) {
return map.entrySet().stream().map(q -> q.getKey());
}
private static <T, U extends Collection<?>> Stream<T> getStreamOfMergedDistinctMappingToN(Map<String, Map<T, U>> map) {
return map.entrySet().stream()
.flatMap(p -> getStreamOfMappingToN(p.getValue())).distinct();
}
What changed is that instead of declaring the input type as ? extends Collection<U>
, the method is accepting Map<T, U>
but U
is constrained to U extends Collection<?>
.
This change represents what you really want to do: you are giving a Map
as input. This map has two types T
and U
. T
can be whatever type we give but U
really needs to be a Collection
of something, i.e. U
must extends Collection<?>
.
To find out why your example doesn't compile, please refer to this answer (or this one): wildcards only works on the 1st level, not deeper. As you found out, you need to add ? extends Map<...>
to counter the fact that the wildcard was not applied recursively.
Still, I would recommend you use the first solution as I feel it gives cleaner code and the proper intent, instead of messing around with wildcards.
Java generics class cast exception
The problem lies here:
data = (Item[]) new Object[MAX_SIZE];
You are instantiating an array of Object
and then you try to cast it as an array of Item
, which throws an exception because Object
does not extend your Item
class, because it does not implement Comparable
. What you would like instead is:
data = new Item[MAX_SIZE];
But you can't do this because Item
is a generic type. If you want to create objects (or arrays of objects) of this type dynamically, you need to pass the Class
object to your GD class's constructor:
import java.lang.reflect.Array;
public class GD<Item extends Comparable<Item>> {
private Item[] data;
private final int MAX_SIZE = 200;
public GD(Class<Item> clazz) {
data = (Item[]) Array.newInstance(clazz, MAX_SIZE);
}
public static void main(String[] args) {
GD<String> g = new GD<String>(String.class);
}
}
Why doesn’t MapString, SetString match MapT, Set??
You're missing the fact that Set<?>
is also used as a generic parameter. And generics are invariant. i.e. when the parameter is Map<String, Set<?>>
, the passed argument must be exactly Map<String, Set<?>
(or a subtype of). Whereas with Set<V>
the type argument is inferred.
You can solve this by using a bounded wildcard:
public <T> int numberOfValues(Map<T, ? extends Set<?>> map) {
...
}
Related Topics
How to Disable or Bypass Hardware Graphics Acceleration(Prism) in Javafx
What Are the Best Use Cases for Akka Framework
How to Keep the Iteration Order of a List When Using Collections.Tomap() on a Stream
JSONmanagedreference VS JSONbackreference
Differencebetween Double.Parsedouble(String) and Double.Valueof(String)
Difference Between Role and Grantedauthority in Spring Security
How to Make Anonymous Inner Classes in Java Static
Cannot Change Version of Project Facet Dynamic Web Module to 3.0
Java - Reading, Manipulating and Writing Wav Files
Java Interfaces Methodology: Should Every Class Implement an Interface
Javafx Using Objects from Maincontroller or Other Controllers in Proper Controller Class
Best Way to Build a Plugin System with Java
Spring Autowiring Class VS. Interface