1

我一直在用 java 编写一个 MongoDB 接口,最近遇到了这个代码障碍。

我有一个插入文档的电话:

insertMongoDocument(String testName, Map<String, Object> input)

我有相应的单元测试:

Writer.insertMongoDocument("TestName", testMap);

测试图的形式是

protected static Map<String, List<?>> testMap;

为什么这是一个非法的论点?是Map<String, List<?>>不是一个Map<String, Object>

4

3 回答 3

4

在 java 中,类型必须与声明的完全匹配。这是给定的

insertMongoDocument(String testName, Map<String, Object> input)

你不能用

Map<String, List<?>> map;
insertMongoDocument("foo", map);

尽管它看起来Map<String, List<?>>应该是 的一个实例Map<String, Object>,但它不是。

这是泛型似乎不遵循基本继承的另一种情况,List<SubClass>不是List<SuperClass>.

如果它是真的,它会导致这个错误:

List<Integer> listI = new ArrayList<Integer>();
List<Number> listN = listI; // compile error, but let's assume OK
listN.add(1.2); // Adding a Double (which is a Number) to a list of Integer - oops!
Integer i = listI.get(0); // BOOM... ClassCastException!

线

List<Number> listN = listI;

由于现在应该是显而易见的原因,这是不允许的,这基本上就是您所看到的:您不能像转换类那样转换泛型类型。

于 2013-09-25T14:33:14.047 回答
2

您需要使用以下签名

insertMongoDocument(String testName, Map<String, ? extends Object> input)

原因是 Java 无法关联参数类型。它试图只应用它知道的规则。在您的原始签名中,它知道它可以接受Object的第二个类型参数Map,然后它发现List<?>哪个不是完全匹配,因此返回错误。需要使用 and 运算符来指定一组适用的类型,而不是完全匹配extendsuper

唯一的 Jon Skeet 对这个话题有一个很好的解释:< 之间有什么区别?超级 E> 和 <? 扩展 E>?

于 2013-09-25T14:34:00.630 回答
0

因为如果它是合法的,你可以将它传递给像 insertMongoDocument 这样的方法,它可能会尝试调用input.put("", new Anything())这会破坏类型安全。

您可以在此处用于签名的最通用类型是insertMongoDocument( String s, Map< String, ? super List< ? > > ).

于 2013-09-25T14:34:10.033 回答