Java-HashMap详解

来源:互联网 发布:七月算法 邹博退出 编辑:程序博客网 时间:2024/05/21 01:47

jdk 1.7

基础知识:Object下的hashcode()方法和equals()方法

HashMap是线程不安全的,可以说是HashTable的轻量级实现


底层实现是数组+链表,即Entry[]

Entry为桶,有next方法指向桶中下一个元素


初始大小(Capacity)为16    注意:1.大小为2的N次幂,2.大小指的是HashMap中Entry的个数

初始因子(Factor)0.75

阀值=Capacity*Factor

一旦大小(size)超过阀值,会扩充HashMap,扩充至当前大小的2倍


可以自定义初始大小(会设置成大于var1、且是2的N次幂的数中最小的那个)

    public HashMap(int var1) {        this(var1, 0.75F);    }

也可以自定义因子

    public HashMap(int var1, float var2) {        if(var1 < 0) {            throw new IllegalArgumentException("Illegal initial capacity: " + var1);        } else {            if(var1 > 1073741824) {                var1 = 1073741824;            }            if(var2 > 0.0F && !Float.isNaN(var2)) {                this.loadFactor = var2;                this.threshold = tableSizeFor(var1);            } else {                throw new IllegalArgumentException("Illegal load factor: " + var2);            }        }    }


put操作

public V put(K key, V value) {        // 1.对key为null的操作(会放在下标为0的位置上)       if (key == null)            return putForNullKey(value);        // 2.计算key对应的hash值       int hash = hash(key.hashCode());        // 3.i为当前hash值在数组中的位置(其值为hash&(table.length - 1))       int i = indexFor(hash, table.length);<pre name="code" class="java">        // 4.如果数组该位置有Entry,则进入循环
 for (Entry<K,V> e = table[i]; e != null; e = e.next) {
       Object k;        // 5.判断:查找Entry<Key,Value>链表中是否已经有了以key值为Key存储的Entry<Key,Value>对象,<pre class="brush:java; toolbar: true; auto-links: false;">            //已经存在,则将Value值覆盖到对应的Entry<Key,Value>对象节点上
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {

V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } // 6.该位置为空 或者 Entry中不存在该key,则新建Entry,插入到这个桶的头部 modCount++; addEntry(hash, key, value, i); return null; }

get操作

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;    }





HashMap性能的提高即修改初始大小以及因子

如果确定会容纳多少个Entry,可以直接将初始大小设置成该数。

如果Entry会特别多,尽量将Factor设置得大些,避免Entry[]利用率不高。


因为扩容的时候,会新建一个Entry[],并将之前的Entry[]中的元素全部重新hash一次,然后加入新的数组,可以看出代价特别大,所以初始大小的选择很重要。



java8中对HashMap作了性能优化,将以前的数组+链表改为了数组+链表/树,为了避免一个链表太长的问题。

修改之后,过长的链表会被转化为树,则HashMap的最坏检索时间复杂度从O(n)降到了O(logn)。



0 0
原创粉丝点击