为什么Map<String, Object>不等于Map<String, ?>

3

我在第二行遇到了错误,所有的项目不都是Object吗?

Map<String, ?> value;  // I get value from some place
Map<String, Object> val = value;
7个回答

5
在Java领域中,泛型中的?表示它可以被替换为任何类型(这个类型可以是有选择地被限制的)。在泛型的情况下,Object不能安全地用这种方法替换为任何类型(因为泛型在运行时被擦除,会遇到泛型和子类型化的问题)。因此,这两者在语义上不是完全相同的,这就是出现编译错误的原因。
举个例子,如果允许这样做,可能会出现以下错误:
Map<String, ?> value = new HashMap<String, String>();
Map<String, Object> val = value; //This line would fail in real life, but assuming it passes...
val.put("Hello", 0); //We could do this!

这显然毫无意义 - HashMap 的类型是 <String, String>,但你却放了一个 Integer 进去!

这就是 ? 表示的不同之处 - 除非你放入一个 Object,否则在地图中放置任何其他东西都会导致编译错误:

value.put("Hello", 0); //Error

值得注意的是,数组不受这些限制的约束,因为它们已被具体化,因此当类型不匹配时可以在运行时抛出有意义的异常。(是否更可取是一个有争议的问题,但个人强烈建议在编译时尽早捕获错误!) 由于泛型不能做到这一点,编译器必须确保其在编译时的安全性。


2
除了关于泛型不是协变的旧误解之外,这是一个很好的解释 - 编译时检查总是优于运行时检查。 - Paul Bellora

0
不是的,它是一个“capture of”,这会导致编译错误,因为显然“?”并不只是指 Object…不过,这似乎正是您想要的 -
Map<String, Object> value;                 // I get an Object
Map<String, ? extends Object> val = value; // Something that is an Object.

或者甚至更好

Map<String, Object> value;  
Map<String, ?> val = value;                // Will take anything...
                                           // Object is more specific.

0

不是的。Map<String, Object> 不是 Map<String, ?> 的超类型,所以这个赋值不是类型安全的。

(然而,Map<String, ?> 是所有 Map<String, T> 的超类型。所以你代码的相反情况是可以工作的。)


0

Map<String, ?>Map<String, Object>都可以潜在地将任何Object作为值。就你所知道的代码而言,这是你可以假设的最具体的内容。(与.get(key)相关)

但是占位符?意味着它可以是不同的具体类型。

例如,Map<String, ?>在运行时允许是一个Map<String, Apple>。即使只有理论上可能有苹果映射的情况下,您也不能将具有不同类型的泛型分配给彼此。


0
使用通配符绑定 ?,您告诉编译器您不知道也不关心泛型类型是什么。如果您只从容器中读取并使用在上限声明的方法(例如,您可以从 Collection<?> 读取并调用 toString(),或者从 List<? extends Closeable> 读取并调用 close()),那么这很好,但是将对象放入集合中是不安全的(它可能真的是一个 Collection<URL>,尝试添加一个 String 将使其损坏)。

0

我是个白痴,把这个留在这里以示羞耻。

C#中泛型的协变和逆变 是一个常见的困惑来源。它在 .NET 4 中被部分修复(并不是说它本身有问题),但让泛型类型按照你所描述的方式工作的新方法是选择性的,而不是追溯性的。


1
然而,这个问题是关于Java的... - Oliver Charlesworth
1
哈!原来是这样。这就是我在喝酒的时候用 iPhone 查看 Stack Overflow 的下场。 - Rex M

-2
    Map<String, ?> value = null;  // initialize 
    Map<String, Object> val = (Map<String, Object>) value; //cast

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接