帮助Java泛型:不能使用“对象”作为“”的参数extends Object“ [英] Help with Java Generics: Cannot use "Object" as argument for "? extends Object"
问题描述
我有以下代码:
import java.util.*;
public class SellTransaction extends Transaction {
private Map<String,? extends Object> origValueMap;
public SellTransaction(Map<String,? extends Object> valueMap) {
super(Transaction.Type.Sell);
assignValues(valueMap);
this.origValueMap=valueMap;
}
public SellTransaction[] splitTransaction(double splitAtQuantity) {
Map<String,? extends Object> valueMapPart1=origValueMap;
valueMapPart1.put(nameMappings[3],(Object)new Double(splitAtQuantity));
Map<String,? extends Object> valueMapPart2=origValueMap;
valueMapPart2.put(nameMappings[3],((Double)origValueMap.get(nameMappings[3]))-splitAtQuantity);
return new SellTransaction[] {new SellTransaction(valueMapPart1),new SellTransaction(valueMapPart2)};
}
}
当我调用<$ c时,代码编译失败$ c> valueMapPart1.put 和 valueMapPart2.put
,其中包含错误:
The code fails to compile when I call valueMapPart1.put
and valueMapPart2.put
, with the error:
The method put(String, capture#5-of ? extends Object) in the type Map is not applicable for the arguments (String, Object)
我在互联网上阅读关于泛型和通配符和捕获,但我仍然不明白什么是错误。我的理解是 Map
的值可以是任何扩展Object的类,我认为可能是多余的,因为所有类都扩展Object。我不能改变泛型到?超级对象
,因为 Map
是由某个库提供的。
I have read on the Internet about generics and wildcards and captures, but I still don't understand what is going wrong. My understanding is that the value of the Map
's can be any class that extends Object, which I think might be redundant, because all classes extend Object. And I cannot change the generics to something like ? super Object
, because the Map
is supplied by some library.
这不是编译?此外,如果我尝试将 valueMap
转换为 Map< String,Object>
,编译器会给出'Unchecked conversion
So why is this not compiling? Also, if I try to cast valueMap
to Map<String,Object>
, the compiler gives me that 'Unchecked conversion' warning.
谢谢!
推荐答案
code> extends ,则它们明确禁止 put
。你应该在修改之前进行防御性复制,因为他们可以合理地将其返回类型更改为在新版本中不可变。如果复制是昂贵的,那么你可以尝试创建一个类型< String,Object>
的地图类型,首先查询它们的地图,然后查询你创建的地图
If the library specifies extends
then they are explicitly disallowing put
. You should defensively copy before modifying, since they can quite legitimately change their return type to be immutable in a new version. If copying is expensive, then you can try creating a map type that is of type <String, Object>
that first queries their map, and then queries some map you create that has your local modifications.
如果你知道他们的返回类型是不可变的,并且你完全拥有它,那么 @SuppressWarnings(unchecked )
注释是解决警告的合法方式,但我会仔细检查这些假设和广泛评论。
If you do know that their return type is immutable and that you solely own it, then the @SuppressWarnings("unchecked")
annotations is a legitimate way to work around the warning, but I would double check those assumptions and comment extensively.
要理解 extends
vs super
,这样看。
由于该值可以是任何扩展 Object
的类型,以下是有效的。
To understand extends
vs super
, look at it this way.
Since the value can be any type that extends Object
, the following is valid.
Map<String, Number> strToNum = new HashMap<String, Number>();
strToNum.put("one", Integer.valueOf(1)); // OK
Map<String, String> strToStr = new HashMap<String, String>();
strToStr.put("one", "1"); // OK
Map<String, ? extends Object> strToUnk = randomBoolean() ? strToNum : strToStr;
strToUnk.put("null", null); // OK. null is an instance of every reference type.
strToUnk.put("two", Integer.valueOf(2)); // NOT OK. strToUnk might be a string to string map
strToUnk.put("two", "2"); // NOT OK. strToUnk might be a string to number map
因此 put
不能真正使用 extends
边界类型。
但是它与读取操作非常好,例如 get
:
So put
doesn't really work with the extends
boundary types.
But it works perfectly well with reading operations like get
:
Object value = strToUnk.get("one"); // We don't know whether value is Integer or String, but it is an object (or null).
如果您希望地图主要使用put而不是get使用super而不是如下扩展:
If you want a map to primarily use with "put" instead of "get", then you can use "super" instead of extends as in:
Map<String, Number> strToNum = new HashMap<String, Number>();
Map<String, Object> strToObj = new HashMap<String, Object>();
Map<String, ? super Number> strToNumBase;
if (randomBoolean()) {
strToNumBase = strToNum;
} else {
strToNumBase = strToObj;
}
// OK. We know that any subclass of Number can be used as values.
strToNumBase.put("two", Double.valueOf(2.0d));
// But now, gets don't work as well.
Number n = strToNumBase.get("one"); // NOT OK.
这篇关于帮助Java泛型:不能使用“对象”作为“”的参数extends Object“的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!