决定不使用完全泛型的get方法的原因是什么 在java.util接口中。地图< K、V >。
为了澄清问题,该方法的签名为
V get(对象键)
而不是
V get(K键)
我想知道为什么(同样的事情为remove, containsKey, containsValue)。
决定不使用完全泛型的get方法的原因是什么 在java.util接口中。地图< K、V >。
为了澄清问题,该方法的签名为
V get(对象键)
而不是
V get(K键)
我想知道为什么(同样的事情为remove, containsKey, containsValue)。
当前回答
原因是包含是由equals和hashCode决定的,它们是Object上的方法,并且都接受Object参数。这是Java标准库的早期设计缺陷。再加上Java类型系统中的限制,它强制依赖于equals和hashCode的任何东西接受Object。
在Java中获得类型安全哈希表和相等性的唯一方法是避免使用Object。equals和Object。hashCode并使用通用的替代品。函数式Java提供的类型类就是为了这个目的:Hash<A>和Equal<A>。提供了HashMap<K, V>的包装器,在其构造函数中接受Hash<K>和Equal<K>。因此,该类的get和contains方法采用类型为K的泛型参数。
例子:
HashMap<String, Integer> h =
new HashMap<String, Integer>(Equal.stringEqual, Hash.stringHash);
h.add("one", 1);
h.get("one"); // All good
h.get(Integer.valueOf(1)); // Compiler error
其他回答
这是对波斯特尔定律的应用,“在你做的事情上要保守,在你接受别人的东西上要自由。”
无论类型如何,都可以执行相等性检查;equals方法定义在Object类上,并接受任何Object作为参数。因此,键等价和基于键等价的操作接受任何Object类型是有意义的。
当映射返回键值时,它通过使用类型参数尽可能多地保存类型信息。
向后兼容,我想。Map(或HashMap)仍然需要支持get(Object)。
合同的表述如下:
更正式地说,如果这个映射包含 从键k到值v的映射 (key==null ?)k = =零: key。equals(k)),然后这个方法 返回v;否则返回null。 (最多可以有一个这样的 映射)。
(我的重点)
因此,成功的键查找取决于输入键对等式方法的实现。它不一定依赖于k的类。
兼容性。
在泛型可用之前,只有get(Object o)。
如果他们改变了这个方法来获得(<K> o),这可能会迫使java用户进行大量的代码维护,只是为了让正常的代码重新编译。
他们可以引入一个额外的方法,比如get_checked(<K> o),并弃用旧的get()方法,这样就有了一个更温和的过渡路径。但出于某种原因,这并没有做到。(我们现在所处的情况是,需要安装findBugs之类的工具来检查get()参数和map的声明键类型<K>之间的类型兼容性。)
我认为与.equals()的语义相关的参数是虚假的。(从技术上讲,他们是正确的,但我仍然认为他们是假的。如果o1和o2没有任何共同的超类,任何头脑正常的设计师都不会让o1.equals(o2)为真。)
谷歌的一名出色的Java编码器Kevin Bourrillion不久前在一篇博客文章中就这个问题写了一篇文章(当然是在Set而不是Map的上下文中)。最相关的句子:
的方法 Collections框架(和谷歌. Collections框架) 收藏图书馆也是)从不 限制其参数的类型 除非是为了预防 收集从破碎。
我不完全确定我是否同意这一原则——例如,. net似乎需要正确的键类型就可以了——但值得遵循博客文章中的推理。(提到。net之后,有必要解释一下,为什么在。net中它不是问题的部分原因是。net中存在更大的问题,即更有限的方差…)