简体   繁体   English

怎样才能使AbstractMap.SimpleEntry可变?

[英]How can AbstractMap.SimpleEntry be mutable?

How can AbstractMap.SimpleEntry be simultaneously 如何同时AbstractMap.SimpleEntry

1) mutable (it's method setValue( ) changes value part of the entry) 1)可变的(它的方法setValue( )更改条目的值部分)

2) having equals() / hashCode() defined including value part of the entry 2)具有equals() / hashCode()定义,包括条目的值部分

3) be the part of Set<Map.Entry<T,K>> entrySet() result 3)是Set<Map.Entry<T,K>> entrySet()结果的一部分

It seems to me, that these three points are controversial. 在我看来,这三点是有争议的。 For example, first two violates contract of Set<> interface, which is not recommending to have mutable elements of the set. 例如,前两个违反了Set<>接口的协定,这不建议使用set的可变元素。

May I be sure, that mutating of Value won't break the map? 我可以确定, Value变化不会破坏地图吗?

Why didn't they did Entry comparable and hashable by key only? 他们为什么不让Entry只能通过键进行比较和散列? This would increase speed in some cases? 在某些情况下会提高速度?

I be sure, that mutating of Value won't break the map? 我敢肯定,价值的变化不会破坏地图吗?

Yes, absolutely. 是的,一点没错。 The HashMap buckets take into account only the key portion of the entry: HashMap存储桶仅考虑条目的关键部分:

public V  [More ...] put(K key, V value) {
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key.hashCode()); // <<== HERE
    ...
}

Why didn't they did Entry comparable and hashable by key only? 他们为什么不让Entry只能通过键进行比较和散列? This would increase speed in some cases? 在某些情况下会提高速度?

The hashCode and equals of Map.Entry have very little relevance: they would be used only if you wanted to hash entries outside the HashMap itself. Map.EntryhashCodeequals的相关性很小:仅当您想对HashMap本身之外的条目进行哈希处理时,才使用它们。 The internal implementation of the EntrySet supplied to the callers of Map.entrySet does not use hashCode / equals of the entry - instead, they use the hash code of only the key portion. 提供给Map.entrySet调用者的EntrySet的内部实现不使用hashCode / equals条目-而是仅使用关键部分的哈希码。 Here is part of a relevant source code for looking up an object in the entry set: 这是用于在条目集中查找对象的相关源代码的一部分:

 public boolean contains(Object o) {
     if (!(o instanceof Map.Entry))
         return false;
     Map.Entry<K,V> e = (Map.Entry<K,V>) o;
     Entry<K,V> candidate = getEntry(e.getKey());
     return candidate != null && candidate.equals(e);
 }

This might be an "opinion" question. 这可能是一个“观点”问题。 Here's my best guess. 这是我最好的猜测。

I think that Set<Map.Entry<T,K>> is made available so that you can iterate over the elements of the set to get all key/value pairs in a map. 我认为可以使用Set<Map.Entry<T,K>>以便您可以迭代集合的元素以获取映射中的所有键/值对。 However, other operations on this Set would be used rarely. 但是,很少使用此Set上的其他操作。 In particular, it seems unlikely that one would use the contains method on this set, which would require building a Map.Entry object of some concrete class that has both a key and a value, to see if it's in this Set<Map.Entry<T,K>> . 特别是,似乎不太可能在此集合上使用contains方法,这需要构建具有键值的某个具体类的Map.Entry对象,以查看它是否在此Set<Map.Entry<T,K>> Since I think contains would be the main use of the hashCode , and since contains would rarely be used, I don't think the hashCode() defined for the Map.Entry is of much use, and thus it shouldn't be a cause for concern. 由于我认为contains将是hashCode的主要用途,并且由于contains将很少被使用,因此我认为为Map.Entry定义的hashCode()不会有太大用处,因此它不应成为原因值得关注。 hashCode() is, of course, present because all Object s have them; hashCode()之所以存在,是因为所有Object都有它们; why they felt a need to define its value formally, I don't know. 他们不知道为什么他们需要正式定义其价值。 But I think it's harmless. 但是我认为这是无害的。

There is no contradiction here. 这里没有矛盾。 The main point that you seem to have missed is that entrySet() does not support adding elements to it . 您似乎错过的要点是entrySet() 不支持向其中添加元素

As such, if a set is well-formed when it is returned by the map, you 这样一来,如果地图返回时集合格式正确,则您

  1. Cannot create a duplicate in the set, as you cannot change keys or add new entries, hence any two entries will remain different 无法在集合中创建重复项,因为您无法更改键或添加新条目,因此任何两个条目将保持不同
  2. Can change the hash code of an Entry , but cannot influence the hash code of the key, so HashMaps will not break - the bucket of the entry is still the same 可以更改Entry的哈希码,但不能影响键的哈希码,因此HashMaps不会中断-条目的存储桶仍然相同
  3. Cannot change the position of the Entry in a sorted map. 无法更改Entry在已排序地图中的位置。

In fact: setValue() does not allow you to change ANYTHING about how the entry is handled by the map, and hence all map contracts will be preserved. 实际上: setValue()不允许您更改有关地图如何处理条目的任何内容,因此将保留所有地图协定。

I cannot attest why exactly equals() and hashCode() were implemented in this specific way, maybe the authors of Java had a use case in mind, I don't. 我无法证明为什么完全以这种特定方式实现了equals()hashCode() ,也许Java的作者想到了用例,但我没有。 (Then again I don't have any use case for those methods in mind at all) (然后我再也不用考虑这些方法的用例了)

The implementation of AbstractMap.SimpleEntry is to be considered a private implementation detail (its not even used by all Map implementations, eg HashMap doesn't use it). AbstractMap.SimpleEntry的实现应被视为私有的实现细节(它甚至没有被所有Map实现使用,例如HashMap不使用它)。

Note that there is no API that exposes this type directly - its arguable that this class could have been made protected or package private instead of public. 请注意, 没有API可以直接公开此类型-可以争论此类可能已被保护或打包为私有而不是公共。

The defining public API is Map.Entry (note that any Map returns a Set). 定义的公共API是Map.Entry(请注意,任何Map都会返回Set)。 Any implementation of Entry needs to conform to this contract, and the hashCode implementation is clearly defined there. Entry的任何实现都需要遵守此合同,并且在那里明确定义了hashCode实现。

A class making use of SimpleEntry will need to override part of the definition to handle setValue() if that is needed by its entrySet() implementation (Take a look at HashMap for an example how its handled). 一类利用SimpleEntry将需要重写定义的一部分来处理的setValue() 如果这是由它的entrySet()实现需要(看看HashMap的一个例子,如何处理它)。 The hashCode of Entry, while documented, is not neccessarily used by the implementation of entrySet(). 虽然有记录, EntrySet()的实现不必使用 Entry的hashCode。

As for "why" is it the way it is: Ask the designer. 至于“为什么”是这样的:请设计师。 Conjecture on my part is that there isn't a deeper reason. 我的猜测是,没有更深层次的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM