关于java中的HashMap实现

时间:2012-08-04 17:01:44

标签: java collections hashmap

我正在尝试对hashmap进行研究,并提出了以下分析:

https://stackoverflow.com/questions/11596549/how-does-javas-hashmap-work-internally/18492835#18492835

Q1你们可以给我看一个简单的地图,你可以在这里展示过程......如何通过使用这个公式详细计算给定键的哈希码..计算位置哈希%(arrayLength-1))其中元素应该被放置(桶号),假设我有这个hashMap

HashMap map=new HashMap();//HashMap key random order.
         map.put("Amit","Java");
         map.put("Saral","J2EE");

Q2有时可能会发生2个不同对象的hashCodes相同。在这种情况下,2个对象将保存在一个存储桶中,并将显示为LinkedList。入口点是最近添加的对象。该对象指的是具有下一个字段的其他对象,因此一个。最后一个条目是指null。你们能用真实的例子告诉我这件事吗!! !!

“Amit”将被分发到第10个桶,因为有点twiddeling。如果没有比特的话,它会进入第7个桶,因为2044535& 15 = 7.如何可能请详细解释整个计算..?

更新了快照......

enter image description here

,另一张图片是......

enter image description here

4 个答案:

答案 0 :(得分:2)

  

通过使用如何详细计算给定键的哈希码   这个公式

如果是String,则由String#hashCode();计算,其实现方式如下:

 public int hashCode() {
    int h = hash;
        int len = count;
    if (h == 0 && len > 0) {
        int off = offset;
        char val[] = value;

            for (int i = 0; i < len; i++) {
                h = 31*h + val[off++];
            }
            hash = h;
        }
        return h;
    }

基本上遵循java doc中的等式

 hashcode = s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

有关此实现的一个有趣的事情是String实际缓存其哈希码。它可以做到这一点,因为String是不可变的。

如果我计算String“Amit”的哈希码,它将产生这个整数:

System.out.println("Amit".hashCode());
>     2044535

让我们通过一个简单的放置到地图,但首先我们必须确定如何构建地图。 关于Java HashMap最有趣的事实是它总是有2 ^ n个桶。因此,如果你调用它,默认的桶数是16,这显然是2 ^ 4。

在此地图上执行put操作,它将首先获取密钥的哈希码。在这个哈希码上发生了一些奇特的比特,以确保糟糕的哈希函数(特别是那些在低位没有差异的哈希函数)不会“重载”一个桶。

实际负责将密钥分发给存储桶的实际功能如下:

 h & (length-1); // length is the current number of buckets, h the hashcode of the key

这仅适用于两种铲斗尺寸的动力,因为它使用&amp;将密钥映射到存储桶而不是模数。

“Amit”将被分发到第10个桶,因为有点twiddeling。如果没有比特的话,它会转到第7个桶,因为2044535 & 15 = 7

现在我们有了索引,我们可以找到存储桶。如果存储桶包含元素,我们必须迭代它们并在找到它时替换相等的条目。 如果在链表中没有找到任何项目,我们只需将其添加到链表的开头。

HashMap中的下一个重要事项是调整大小,因此如果地图的实际大小超过阈值(由当前桶数和loadfactor确定,在我们的情况下为16 * 0.75 = 12 )它将调整后备阵列的大小。 调整大小总是2 *当前桶的数量,保证是2的幂,不破坏找到桶的功能。

由于存储桶数量发生变化,我们必须重新整理表格中的所有当前条目。 这是非常昂贵的,所以如果您知道有多少项,您应该使用该计数初始化HashMap,这样就不必一直调整大小。

答案 1 :(得分:0)

Q1:查看hashCode()对象

String方法实现

Q2:创建简单类并将其hashCode()方法实现为return 1。这意味着每个具有该类的对象将具有相同的hashCode,因此将保存在HashMap中的同一个存储桶中。

答案 2 :(得分:0)

了解哈希码有两个基本要求:

  1. 当为给定对象重新计算哈希码时(内部未以改变其身份的方式进行更改),它必须生成与先前计算相同的值。同样,两个“相同”的对象必须生成相同的哈希码。
  2. 当为两个不同的对象计算哈希码时(从内部内容的角度来看,这些对象不被视为“相同”),两个哈希码的概率应该很高。
  3. 如何实现这些目标是研究这些目标的数学老师非常感兴趣的主题,但理解细节对理解哈希表的工作方式并不重要。

答案 3 :(得分:-1)

import java.util.Arrays;
public class Test2 {
public static void main(String[] args) {
    Map<Integer, String> map = new Map<Integer, String>();
    map.put(1, "A");
    map.put(2, "B");
    map.put(3, "C");
    map.put(4, "D");
    map.put(5, "E");

    System.out.println("Iterate");
    for (int i = 0; i < map.size(); i++) {

        System.out.println(map.values()[i].getKey() + " : " + map.values()[i].getValue());
    }

    System.out.println("Get-> 3");
    System.out.println(map.get(3));

    System.out.println("Delete-> 3");
    map.delete(3);

    System.out.println("Iterate again");
    for (int i = 0; i < map.size(); i++) {

        System.out.println(map.values()[i].getKey() + " : " + map.values()[i].getValue());
    }
}

}

class Map<K, V> {

private int size;
private Entry<K, V>[] entries = new Entry[16];

public void put(K key, V value) {

    boolean flag = true;
    for (int i = 0; i < size; i++) {

        if (entries[i].getKey().equals(key)) {
            entries[i].setValue(value);
            flag = false;
            break;
        }
    }

    if (flag) {
        this.ensureCapacity();
        entries[size++] = new Entry<K, V>(key, value);
    }
}

public V get(K key) {

    V value = null;

    for (int i = 0; i < size; i++) {

        if (entries[i].getKey().equals(key)) {
            value = entries[i].getValue();
            break;
        }
    }
    return value;
}

public boolean delete(K key) {
    boolean flag = false;
    Entry<K, V>[] entry = new Entry[size];
    int j = 0;
    int total = size;
    for (int i = 0; i < total; i++) {

        if (!entries[i].getKey().equals(key)) {
            entry[j++] = entries[i];
        } else {
            flag = true;
            size--;
        }
    }

    entries = flag ? entry : entries;
    return flag;
}

public int size() {
    return size;
}

public Entry<K, V>[] values() {
    return entries;
}

private void ensureCapacity() {

    if (size == entries.length) {
        entries = Arrays.copyOf(entries, size * 2);
    }
}

@SuppressWarnings("hiding")
public class Entry<K, V> {

    private K key;
    private V value;

    public K getKey() {
        return key;
    }

    public V getValue() {
        return value;
    }

    public void setValue(V value) {
        this.value = value;
    }

    public Entry(K key, V value) {
        super();
        this.key = key;
        this.value = value;
    }

}
}