Hashmap采用链地址法来处理冲突:

  void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }

        createEntry(hash, key, value, bucketIndex);
    }
   void createEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<>(hash, key, value, e);
        size++;
    }
    

这个e就被赋值到next里面去了。
get的时候也是用链表来个get:

 final Entry<K,V> getEntry(Object key) {
        if (size == 0) {
            return null;
        }

        int hash = (key == null) ? 0 : hash(key);
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) { //注意这个大的for循环。循环一个链栈。next自然就在里面
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k))))
                return e;
        }
        return null;
    }

HashMap产生的原因是不同的key会产生相同的数组下标地址。数组下标地址里面存了链表。查询的时候,先table[indexFor(hash, table.length)]找到数组下标,再根据key来寻找结果。
http://zhangshixi.iteye.com/blog/672697

什么是加载(装载因子):
加载因子是表示Hsah表中元素的填满的程度.若:加载因子越大,填满的元素越多,好处是,空间利用率高了,但:冲突的机会加大了.反之,加载因子越小,填满的元素越少,好处是:冲突的机会减小了,但:空间浪费多了.

冲突的机会越大,则查找的成本越高.反之,查找的成本越小.因而,查找时间就越小.

因此,必须在 "冲突的机会"与"空间利用率"之间寻找一种平衡与折衷. 这种平衡与折衷本质上是数据结构中有名的"时-空"矛盾的平衡与折衷.

loadfactor默认0.75,就是说差不多快满(默认取3/4)的时候重新hash/resize,这样可以避免hashmap里面每个table元素上的链表长度过长,影响hashmap的效率;
默认加载因子,加载因子是一个比例,当HashMap的数据大小>=容量*加载因子时,HashMap会将容量扩容
static final float DEFAULT_LOAD_FACTOR = 0.75f;
当实际数据大小超过threshold时,HashMap会将容量扩容,threshold=容量*加载因子
int threshold;
threshold是每次都要计算好的值。(扩容一次就计算一次)

HashMap本身存储的也是数组。。
Hashtable的应用非常广泛,HashMap是新框架中用来代替Hashtable的类,也就是说建议使用HashMap,不要使用Hashtable
1.Hashtable的方法是同步的,HashMap未经同步
2.Hashtable直接使用对象的hashCode
3.Hashtable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数


happyfish
2.4k 声望66 粉丝

[链接]