我正在尝试编写一个通用函数,它将接受以下两种数据类型
Map <Integer, Map<Integer, Long>>
Map <Integer, Map<Integer, Double>>
我的功能看起来像这样,
function(Map<Integer, Map<Integer, ? extends Number>> arg) {}
但我收到一个不兼容的类型错误。它适用于地图,但不适用于地图地图。我无法理解为什么?有没有办法做到这一点?
你可以尝试类似的东西
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
}
为什么不只是参数化方法?
public <T extends Number> void function(Map<Integer, Map<Integer, T>>) { ... }
我发现通配符捕获往往会使人们混淆它的真正作用。
Map<Integer, ? extends Number>
真正意味着任何Map
其键是Integer
并且其值是派生自 的类型Number
。这意味着Map<Integer, Integer>,
Map<Integer,Long>
。
出于这个原因,您永远无法真正添加到这些集合中,因为通配符编译器无法判断要添加的真正类型是什么。
首先让我们通过使用Set
s 来减少问题:
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>
toSet<? extends Number>
原因是泛型不是协变的。编译器会阻止您将 a 分配给Set<Set<Long>>
,Set<Set<? extends Number>>
原因与它不允许您将 a 分配给 a 的原因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) { }
static void test(Map<Integer, Map<Integer, ? extends Number>> a) { }
这实际上对我来说很好(JavaSE-1.6)。