为什么Map <string,object =“”>不等于Map <string,?=“”> </string,> </string,>

时间:2013-12-24 00:46:00

标签: java generics map

我在第二行收到错误,并非所有项目都是Object

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

7 个答案:

答案 0 :(得分:4)

泛型中的?(在Java土地中)表示它可以替换任何类型(此类型可以选择有界。)对于泛型,Object 不能< / em>以这种方式安全地替换任何类型(它会遇到generics and subtyping的问题,因为泛型会在运行时被删除。)

因此,这两者在语义上并不像您最初预期的那样相同,因此编译错误。

如果允许这样做可能会出错,可以这样做:

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

值得注意的是,数组不具有这些相同的限制,因为它们实现了,因此在发生类型不匹配时可以在运行时抛出有意义的异常。 (这是否更可取是一个争论的问题,但我个人更喜欢在编译时尽早发现错误!)由于泛型不能这样做,编译器必须确保它们在编译时的安全性。

答案 1 :(得分:1)

我是个白痴,为了我的耻辱而离开这里。

Covariance and contravariance with generic types in c#是混淆的常见原因。它在.NET 4中是有点固定的(不是它本身就被破坏了),但制作泛型类型的新方法是按照你所描述的方式工作,而不是追溯。

答案 2 :(得分:0)

没有。 Map<String, Object>不是Map<String, ?>的超类型,因此分配不是类型安全的。

(但是,Map<String, ?> 是所有Map<String, T>的超类型。因此,代码的反面将起作用。)

答案 3 :(得分:0)

Map<String, ?>Map<String, Object>都可以将Object作为值。据您所知,在您的代码中,您可以假设最具体。 (与.get(key)相关)

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

E.g。 Map<String, ?>在运行时允许为Map<String, Apple>。并且您不能将具有不同类型的泛型分配给彼此。即使只有理论上有机会你可以拥有苹果地图。

答案 4 :(得分:0)

不,它是capture of并导致编译错误,因为显然?并不仅仅意味着对象......但是,这就是你想要的 -

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.

答案 5 :(得分:0)

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

答案 6 :(得分:-2)

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