Java HashMap与散列

来源:互联网 发布:淘宝上怎么做网拍模特 编辑:程序博客网 时间:2024/05/20 14:15

HashMap内部存储和查找采用的是散列法。

先看HashMap的默认构造函数:

public HashMap() {        this.loadFactor = DEFAULT_LOAD_FACTOR;//默认的装填因子0.75        threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);        table = new Entry[DEFAULT_INITIAL_CAPACITY];//默认的初始数组长度为16        init();    }

里面定义了一个哈希表table,哈希表里放的元素是Entry,Entry里定义了如下成员变量:

final K key;V value;Entry<K,V> next;
value是具体的数据元素,key是value的关键字。然后定义了自身类型的变量,所以这是一个自引用类,由此可知,HashMap解决哈希冲突采用的是方法是开散列法,也就是链表法。

接着看存储方法,也就是 put方法:

public V put(K key, V value) {        if (key == null)            return putForNullKey(value);//有一个专门存放key为null的方法        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;}
从key到最后的哈希值(索引),调用了3个方法:

1.key.hashCode()(如果没重写Object的hashCode方法,返回的就是该对象的内部地址转换成的一个整数,这也是为什么Java需要为Object类定义hashCode方法,这是一个本地方法)

2.HashMap.hash()

static int hash(int h) {        // This function ensures that hashCodes that differ only by        // constant multiples at each bit position have a bounded        // number of collisions (approximately 8 at default load factor).        h ^= (h >>> 20) ^ (h >>> 12);        return h ^ (h >>> 7) ^ (h >>> 4);}

3.HashMap.indexFor()

/**     * Returns index for hash code h.     */    static int indexFor(int h, int length) {        return h & (length-1);    }

for循环判断是否已放入该元素,然后是核心的添加元素的方法addEntry:

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);//哈希表扩容}
先取出原来的元素,然后放入新添加的元素。看一下Entry的构造方法:

Entry(int h, K k, V v, Entry<K,V> n) {            value = v;            next = n;            key = k;            hash = h;}
这里把新添加的元素指向了原来的元素,于是我们知道,越早放入的元素,离table就越远。

到此,元素的存储基本结束。另外附上HashMap的内存结构图:



检索的方法就不多说了,怎么存就怎么取,代码如下:

public V get(Object key) {        if (key == null)            return getForNullKey();        int hash = hash(key.hashCode());        for (Entry<K,V> e = table[indexFor(hash, table.length)];             e != null;             e = e.next) {            Object k;            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))                return e.value;        }        return null;    }




0 0
原创粉丝点击