0

我有以下代码:

String test = "[{\"color\":\"red\"}]";
Class<? extends Base> baseObject = Base.class;
Collection<? extends Base> elements = new ArrayList<Base>();
 if (test.startsWith("[")) {
    elements.addAll(new ObjectMapper().readValue(test, Collection.class));
 } else {
   elements.add(new ObjectMapper().readValue(test, baseObject));
}

不过我继续

elements.addAll(new ObjectMapper().readValue(test, Collection.class));

编译警告:

The expression of type Collection needs unchecked conversion to conform to Collection<? extends capture#1-of ? extends Base>

并且对于elements.add(new ObjectMapper().readValue(test, baseObject));

编译错误:

The method add(capture#2-of ? extends Base) in the type Collection<capture#2-of ? extends Base> is not applicable for the arguments (capture#3-of ? extends Base)

怎么了?

4

2 回答 2

2

错误很容易解释。您的集合被定义为保存扩展类的实例BaseObjectMapper.readValue定义如下:

public <T> T readValue(JsonParser jp, Class<T> valueType)

这意味着它返回指定为第二个参数的类的实例。如果第二个参数是Collection.class这个方法返回Collection。只是Collection,不是Collection<? extends Base>,不是Collection<Base>。因此,java 编译器无法确定您是否要将包含正确对象的集合放入elements定义为Collection<? extends Base>. 此外,java 语法不允许作为参数类提供泛型,即您不能调用readValue(c, Collection<Base>.class).

第二种情况更复杂。baseObject定义为Class<? extends Base>elementscollection 也被定义为Class<? extends Base>。所以有什么问题。问题出在?. 问号的意思是“扩展 Base 的东西”。但在这两种情况下,这些都是 2 个不同的“东西”。

解决方案可以是Class<Base>在这两种情况下将集合的定义更改为或使用一个类或方法泛型参数,例如:

public <T extends Base> myMethod() {
    Class<T> baseObject = Base.class;
    Collection<T> elements = new ArrayList<T>();
    elements.add(new ObjectMapper().readValue(test, baseObject));
}

现在两者都baseObject使用确实 extendselements的相同类型。TBase

于 2013-06-11T15:26:36.580 回答
1

您不能使用通配符类型将东西添加到集合中(根据 Brian 的说法,使用 没有明确的下限super;这确实有些道理,因为子类总是可以转换为它的超类之一,但我以前没有使用过超有界通配符,所以我不太确定细节)。

http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

具体来说:

因为我们不知道元素类型c代表什么,所以我们不能向它添加对象。该add()方法接受 type 的参数E,即集合的元素类型。当实际类型参数为?时,它代表某种未知类型。我们传递给的任何参数add都必须是这种未知类型的子类型。因为我们不知道那是什么类型,所以我们不能传入任何东西。唯一的例外是null,它是每个类型的成员。

类型擦除是……嗯,你知道的。

于 2013-06-11T15:01:41.570 回答