决定不使用完全泛型的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
其他回答
合同的表述如下:
更正式地说,如果这个映射包含 从键k到值v的映射 (key==null ?)k = =零: key。equals(k)),然后这个方法 返回v;否则返回null。 (最多可以有一个这样的 映射)。
(我的重点)
因此,成功的键查找取决于输入键对等式方法的实现。它不一定依赖于k的类。
原因是包含是由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
向后兼容,我想。Map(或HashMap)仍然需要支持get(Object)。
还有一个更重要的原因,它在技术上不能做到,因为它破坏了地图。
Java has polymorphic generic construction like <? extends SomeClass>. Marked such reference can point to type signed with <AnySubclassOfSomeClass>. But polymorphic generic makes that reference readonly. The compiler allows you to use generic types only as returning type of method (like simple getters), but blocks using of methods where generic type is argument (like ordinary setters). It means if you write Map<? extends KeyType, ValueType>, the compiler does not allow you to call method get(<? extends KeyType>), and the map will be useless. The only solution is to make this method not generic: get(Object).
I was looking at this and thinking why they did it this way. I don't think any of the existing answers explains why they couldn't just make the new generic interface accept only the proper type for the key. The actual reason is that even though they introduced generics they did NOT create a new interface. The Map interface is the same old non-generic Map it just serves as both generic and non-generic version. This way if you have a method that accepts non-generic Map you can pass it a Map<String, Customer> and it would still work. At the same time the contract for get accepts Object so the new interface should support this contract too.
在我看来,他们应该添加一个新的接口,并在现有的集合上实现这两个接口,但他们决定支持兼容接口,即使这意味着get方法的设计更糟糕。注意,集合本身与现有方法兼容,只有接口不兼容。