【发布时间】:2009-11-15 21:46:22
【问题描述】:
我正在开发一个需要将键值对放入 hashmap 的解析器。
但是一个键可以有多个值,我可以用这种方式来做
HashMap<String,ArrayList<String>>.
但是如果键的数量非常大并且它开始与其他键的哈希码匹配会发生什么。
这会重写前一个键的值吗?
【问题讨论】:
标签: java collections hashmap
我正在开发一个需要将键值对放入 hashmap 的解析器。
但是一个键可以有多个值,我可以用这种方式来做
HashMap<String,ArrayList<String>>.
但是如果键的数量非常大并且它开始与其他键的哈希码匹配会发生什么。
这会重写前一个键的值吗?
【问题讨论】:
标签: java collections hashmap
如果映射中键的哈希与现有键冲突,映射将重新排列或将键保留在该哈希下的列表中。没有任何键会被发生的其他键覆盖,因此请在同一个存储桶中进行排序。
如果多个线程同时使用映射,如果映射不处理并发访问,您可能希望同步对映射的访问。 (一些标准 Map 有,其他没有。Java Collections 包确实包含添加同步的包装类。)
【讨论】:
首先,看看Google Collections Multimap,它可以让您为每个键分配多个值,而无需手动维护值列表。
其次,no - 具有相同哈希码的键不会发生冲突。不保证或要求哈希码是唯一的; HashMap 在内部为每个哈希码维护一个键/值对的“桶”。
【讨论】:
IdentityHashmap。在那里,“身份哈希码”和== 用于密钥,而不管hashcode 和equals 是如何被覆盖的。
HashMap 是碰撞安全的:查看 the sourcecode 的 put:
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
和
/**
* Adds a new entry with the specified key, value and hash code to
* the specified bucket. It is the responsibility of this
* method to resize the table if appropriate.
*
* Subclass overrides this to alter the behavior of put method.
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
表的条目就像一个链表。当您将新条目放入同一个存储桶时,它只会添加到链表中。
【讨论】:
如果它等于前一个键,它只会覆盖前一个键的值。有线性探测、重新散列、存储桶等方法,在散列实现中使用这些方法来防止散列码冲突覆盖不相等的键。
【讨论】:
我认为冲突与插入相同的密钥不同。当单独的键散列到相同的值时会发生冲突。据了解,任何实现 Map 接口的人都应该具备处理碰撞的能力。因此,您的问题的答案是,是的,Java 中的 HashMap 确实可以安全地处理冲突。
但是,如果插入了相同的密钥,则与完全相同的密钥关联的先前值将被更新/覆盖。这本身不被认为是碰撞,而是直接破坏已经存在的东西。
【讨论】: