2

我正在尝试编写一个通用函数,它将接受以下两种数据类型

Map <Integer, Map<Integer, Long>>
Map <Integer, Map<Integer, Double>>

我的功能看起来像这样,

function(Map<Integer, Map<Integer, ? extends Number>> arg) {}

但我收到一个不兼容的类型错误。它适用于地图,但不适用于地图地图。我无法理解为什么?有没有办法做到这一点?

4

4 回答 4

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
}
于 2012-07-23T00:10:43.593 回答
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>

出于这个原因,您永远无法真正添加到这些集合中,因为通配符编译器无法判断要添加的真正类型是什么。

于 2012-07-23T00:13:10.983 回答
2

首先让我们通过使用Sets 来减少问题:

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) { }
于 2012-07-23T00:48:27.240 回答
0
static void test(Map<Integer, Map<Integer, ? extends Number>> a) { }

这实际上对我来说很好(JavaSE-1.6)。

于 2012-07-23T00:17:07.687 回答