Reputation: 846
I am trying to write a generic function which will accept both of the following data types
Map <Integer, Map<Integer, Long>>
Map <Integer, Map<Integer, Double>>
My function looks like this,
function(Map<Integer, Map<Integer, ? extends Number>> arg) {}
But I am getting an incompatible type error. It works for a Map, but not for map of Maps. I am not able to understand why? Is there any way to do this?
Upvotes: 2
Views: 621
Reputation: 55233
First let's reduce the problem by using Set
s instead:
Set<Set<Long>> longSetSet = null;
Set<Set<Double>> doubleSetSet = null;
Set<Set<? extends Number>> someNumberSetSet;
// try assigning them
someNumberSetSet = longSetSet; //
someNumberSetSet = doubleSetSet; // compiler errors - incompatible types
At first glance you might wonder why this assignment is illegal, since after all you can assign a Set<Long>
to Set<? extends Number>
The reason is that generics are not covariant. The compiler prevents you from assigning a Set<Set<Long>>
to Set<Set<? extends Number>>
for the same reason it won't let you assign a Set<Long>
to a Set<Number>
. See the linked answer for more details.
As a workaround, you can use a type parameter in your method signature as other answers have suggested. You can also use another wildcard to make the assignment legal:
Set<? extends Set<? extends Number>> someNumberSetSet;
someNumberSetSet = longSetSet; //
someNumberSetSet = doubleSetSet; // legal now
Or in your example:
function(Map<Integer, ? extends Map<Integer, ? extends Number>> arg) { }
Upvotes: 2
Reputation: 11815
Why not just parameterize the method?
public <T extends Number> void function(Map<Integer, Map<Integer, T>>) { ... }
I've found that the wildcard capture tends to confuse people as to what it really does.
Map<Integer, ? extends Number>
really means any Map
whose key is Integer
and whose value is a type derived from Number
. This means Map<Integer, Integer>,
Map<Integer,Long>
.
For this reason, you can never really add to those collections, because of the wildcard the compiler can't tell what the real type is in order to add.
Upvotes: 2
Reputation: 559
static void test(Map<Integer, Map<Integer, ? extends Number>> a) { }
This actually works just fine for me (JavaSE-1.6).
Upvotes: 0
Reputation: 124275
You could try something like
static <T extends Number> void function(Map<Integer, Map<Integer, T>> map) {}
public static void main(String[] args) {
Map<Integer, Map<Integer, Long>> map1 = new HashMap<Integer, Map<Integer, Long>>();
Map<Integer, Map<Integer, Double>> map2 = new HashMap<Integer, Map<Integer, Double>>();
Map<Integer, Map<Integer, String>> map3 = new HashMap<Integer, Map<Integer, String>>();
function(map1);
function(map2);
function(map3);// <-- compilation error here, String is not Number
}
Upvotes: 3