如果重写哈希代码,Hashmap键如何表现,它只返回一个常数?

时间:2014-10-31 12:28:46

标签: java hashmap hashcode

我对Java Hashmap提出了一个小问题。如果我覆盖hashCode方法,那么:

@Override
public int hashCode(){
  return 9;
}

这将导致所有HashMap键具有相同的索引。它们会被放置在地图中的链表结构中,还是地图只包含替换所有其他键的最后一个键?

3 个答案:

答案 0 :(得分:4)

它们将被放置在地图中的链表结构中,假设您没有覆盖equals方法以始终返回true。不同的键可能具有相同的hashCode,但如果所有键具有相同的hashCode,则HashMap将成为链接列表,这首先会破坏使用此结构的目的。

您可以在HashMap实施中自行查看:

/**
 * 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 the map
 *         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()); // hash would always be the same if hashCode is constant
    int i = indexFor(hash, table.length); // i would always be the same if hashCode is constant
    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))) { // the key is searched using the
                                                                       // equals method
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    modCount++;
    addEntry(hash, key, value, i);
    return null;
}

答案 1 :(得分:1)

Hashcode值用于减少对象的搜索时间。 哈希码值对于不同的对象不一定是唯一的。实际上,hashCode()方法可以以这样的方式被覆盖,即它为所有对象返回一个常量整数(但这会破坏hashCode()方法的目的)。但是,类Object的默认实现确实为每个对象返回一个唯一的整数,因为它将对象的内部地址映射为整数并返回相同的整数。但这不是一项要求

答案 2 :(得分:0)

它是否显示为链表是有争议的,因为它没有在文档中说明。但是,它肯定会保留所有项目的唯一键(即将true返回equals方法的键。)

class Nine {

    final String value;

    public Nine(String value) {
        this.value = value;
    }

    @Override
    public int hashCode() {
        return 9;
    }

    @Override
    public boolean equals(Object it) {
        return it instanceof Nine && ((Nine) it).value.equals(value);
    }

    @Override
    public String toString() {
        return value;
    }
}

class AlwaysNine extends Nine {

    public AlwaysNine(String value) {
        super(value);
    }

    @Override
    public boolean equals(Object it) {
        return it instanceof Nine;
    }
}

public void test() {
    System.out.println("Hello");
    Map<Nine, String> testMap = new HashMap<Nine, String>();
    testMap.put(new Nine("Nine"), "Nine");
    testMap.put(new Nine("nine"), "nine");
    testMap.put(new AlwaysNine("nIne"), "nIne");
    System.out.println(testMap);
}

打印

{Nine=nIne, nine=nine}

证明只有覆盖equals才会强制键看起来像预期的那样......因为hashCode仅用于选择放置对象的存储桶。