Java Map.get(对象键)不是(完全)通用的原因是什么
决定不使用完全通用的get方法的原因是什么 在的界面中 为了澄清这个问题,方法的签名是Java Map.get(对象键)不是(完全)通用的原因是什么,java,generics,collections,map,Java,Generics,Collections,Map,决定不使用完全通用的get方法的原因是什么 在的界面中 为了澄清这个问题,方法的签名是 V get(对象键) 而不是 V get(K键) 我想知道为什么(对于remove、containsKey、containsValue都是一样的)。我猜是向后兼容Map(或HashMap)仍需支持get(Object)合同表述如下: 更正式地说,如果此地图包含 从键k到值v的映射,如 (key==null?k==null: 键。等于(k)),则此方法 返回v;否则返回null。 (最多可以有一个 映射。) (
V get(对象键)
而不是
V get(K键)
我想知道为什么(对于
remove、containsKey、containsValue都是一样的)。我猜是向后兼容Map
(或HashMap
)仍需支持get(Object)
合同表述如下:
更正式地说,如果此地图包含
从键k到值v的映射,如
(key==null?k==null:
键。等于(k)),则此方法
返回v;否则返回null。
(最多可以有一个
映射。)
(我的重点)
因此,成功的键查找取决于输入键对相等方法的实现。这并不一定取决于k的阶级。谷歌一位出色的Java程序员凯文·布瑞利昂(Kevin Bourrillion)不久前就写过这个问题(无可否认是在Set
而不是Map
的背景下写的)。最相关的一句话:
Java的方法是一致的
集合框架(和Google
收藏(图书馆也一样)永远不会
限制其参数的类型
除非有必要预防
这些收藏品不会被损坏
我不完全确定我是否同意这一原则——例如,.NET似乎可以要求正确的键类型——但值得遵循博客文章中的推理。(提到.NET后,值得解释的是,它在.NET中不是问题的部分原因是.NET中存在更大的问题,差异更有限……)原因是包含由equals
和hashCode
确定,这两种方法都是对对象
的方法,并且都采用对象
参数。这是Java标准库中的早期设计缺陷。再加上Java类型系统的局限性,它强制依赖于equals和hashCode的任何东西都接受对象
在Java中拥有类型安全哈希表和相等的唯一方法是避免使用Object.equals
和Object.hashCode
,并使用泛型替换。附带的类型类仅用于此目的:和。提供的包装器在其构造函数中采用散列
和相等
。此类的get
和包含方法,因此采用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
HashMap h=
新的HashMap(Equal.stringEqual,Hash.stringHash);
h、 添加(“一”,1);
h、 获取(“一”);//一切都好
h、 get(Integer.valueOf(1));//编译错误
正如其他人所提到的,get()
等的原因不是泛型的,因为您正在检索的条目的键不必与您传递给get()
的对象的类型相同;该方法的规范只要求它们相等。这源于equals()
方法如何将对象作为参数,而不仅仅是对象的类型
虽然许多类都定义了equals()
,使其对象只能与自己类的对象相等,这一点通常是正确的,但Java中有许多地方并非如此。例如,List.equals()
的规范指出,如果两个列表对象都是列表并且具有相同的内容,则它们是相等的,即使它们是List
的不同实现。所以回到这个问题中的例子,根据方法的规范,可以有一个映射
,我可以用LinkedList
作为参数调用get()
,它应该检索一个键,它是一个具有相同内容的列表。如果get()
是泛型的并且限制了它的参数类型,这将是不可能的。我认为泛型教程的这一部分解释了这种情况(我的重点):
“您需要确保通用API没有过度限制;它必须
继续支持API的原始合同。
来自java.util.Collection。预泛型API如下所示:
interface Collection {
public boolean containsAll(Collection c);
...
}
将其泛化的天真尝试是:
interface Collection<E> {
public boolean containsAll(Collection<E> c);
...
}
接口集合{
公共图书馆(c组);
...
}
虽然这肯定是类型安全的,但它不符合API的原始合同。
containsAll()方法适用于任何类型的传入集合
如果传入集合确实只包含E的实例,则成功,但:
- 传入文件的静态类型
收集可能会有所不同
因为打电话的人不知道电话号码
正在创建的集合的精确类型
通过了,或者可能是因为它是一个
集合,其中S是
E
- 非常好
调用containsAll()的合法性
一个不同类型的集合
例行程序应该有效,返回false。“
这是一种“做事要保守,接受别人的东西要自由”的应用
无论类型如何,都可以执行相等性检查;equals
方法在对象
类上定义,并接受任何对象
作为参数。因此,接受任何对象
类型对于键等价和基于键等价的操作是有意义的
当映射返回键值时,它通过使用type参数保存尽可能多的类型信息。还有一个更重要的原因,它不能在技术上完成,因为它会破坏映射
Java有多态的泛型结构,比如,我在看这篇文章,并思考他们为什么这样做。我认为现有的任何答案都不能解释为什么他们不能直接