帮助Java泛型:不能使用“对象”作为“”的参数extends Object“ [英] Help with Java Generics: Cannot use "Object" as argument for "? extends Object"

查看:249
本文介绍了帮助Java泛型:不能使用“对象”作为“”的参数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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆