我正在尝试编写一个接受以下两种数据类型的通用函数
Map <Integer, Map<Integer, Long>>
Map <Integer, Map<Integer, Double>>
我的功能看起来像这样,
function(Map<Integer, Map<Integer, ? extends Number>> arg) {}
但是我收到了一个不兼容的类型错误。它适用于地图,但不适用于地图地图。我无法理解为什么?有没有办法做到这一点?
答案 0 :(得分:3)
您可以尝试类似
的内容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
}
答案 1 :(得分:2)
为什么不直接参数化方法?
public <T extends Number> void function(Map<Integer, Map<Integer, T>>) { ... }
我发现通配符捕获往往会让人们对它的真实含义感到困惑。
Map<Integer, ? extends Number>
实际上是指任何Map
,其密钥为Integer
,其值是从Number
派生的类型。这意味着Map<Integer, Integer>,
Map<Integer,Long>
。
出于这个原因,你永远不能真正添加到这些集合,因为通配符编译器无法分辨真正的类型是为了添加。
答案 2 :(得分:2)
首先,让我们使用Set
来减少问题:
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
乍一看,您可能想知道为什么这项任务是非法的,因为毕竟您可以将Set<Long>
分配给Set<? extends Number>
原因是generics are not covariant。编译器阻止您将Set<Set<Long>>
分配给Set<Set<? extends Number>>
,原因与您无法将Set<Long>
分配给Set<Number>
的原因相同。有关详细信息,请参阅链接的答案。
作为一种变通方法,您可以在方法签名中使用类型参数,如其他答案所示。您还可以使用另一个通配符使分配合法:
Set<? extends Set<? extends Number>> someNumberSetSet;
someNumberSetSet = longSetSet; //
someNumberSetSet = doubleSetSet; // legal now
或者在你的例子中:
function(Map<Integer, ? extends Map<Integer, ? extends Number>> arg) { }
答案 3 :(得分:0)
static void test(Map<Integer, Map<Integer, ? extends Number>> a) { }
这实际上对我来说很合适(JavaSE-1.6)。