决定不使用完全泛型的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)。
当前回答
我们正在做大的重构,我们错过了这个强类型的get(),以检查我们是否错过了旧类型的get()。
但是我发现了编译时间检查的变通/丑陋的技巧:创建Map接口,强类型get, containsKey, remove…然后放到java中。您的项目的Util包。
你只调用get()就会得到编译错误,…对于错误的类型,其他的编译器似乎都可以(至少在eclipse kepler内部)。
不要忘记在检查构建后删除此接口,因为这不是您在运行时想要的。
其他回答
谷歌的一名出色的Java编码器Kevin Bourrillion不久前在一篇博客文章中就这个问题写了一篇文章(当然是在Set而不是Map的上下文中)。最相关的句子:
的方法 Collections框架(和谷歌. Collections框架) 收藏图书馆也是)从不 限制其参数的类型 除非是为了预防 收集从破碎。
我不完全确定我是否同意这一原则——例如,. net似乎需要正确的键类型就可以了——但值得遵循博客文章中的推理。(提到。net之后,有必要解释一下,为什么在。net中它不是问题的部分原因是。net中存在更大的问题,即更有限的方差…)
合同的表述如下:
更正式地说,如果这个映射包含 从键k到值v的映射 (key==null ?)k = =零: key。equals(k)),然后这个方法 返回v;否则返回null。 (最多可以有一个这样的 映射)。
(我的重点)
因此,成功的键查找取决于输入键对等式方法的实现。它不一定依赖于k的类。
我认为泛型教程的这一部分解释了这种情况(我的重点):
“你需要确保通用API没有过度限制;它必须 继续支持原API合同。再来看一些例子 从java.util.Collection。泛型前API看起来像这样:
interface Collection {
public boolean containsAll(Collection c);
...
}
一种天真的概括是:
interface Collection<E> {
public boolean containsAll(Collection<E> c);
...
}
虽然这肯定是类型安全的,但它不符合API的原始契约。 containsAll()方法适用于任何类型的传入集合。它只会 如果传入的集合真的只包含E的实例,则成功,但是:
传入的静态类型 收藏可能有所不同 因为调用者不知道 集合的精确类型 传入,或者因为它是 集合<S>,其中S是a E的子类型。 它是完美的 使用containsAll()调用是合法的 不同类型的集合。的 程序应该工作,返回false。”
向后兼容,我想。Map(或HashMap)仍然需要支持get(Object)。
这是对波斯特尔定律的应用,“在你做的事情上要保守,在你接受别人的东西上要自由。”
无论类型如何,都可以执行相等性检查;equals方法定义在Object类上,并接受任何Object作为参数。因此,键等价和基于键等价的操作接受任何Object类型是有意义的。
当映射返回键值时,它通过使用类型参数尽可能多地保存类型信息。