Android7.1源码阅读001-HashMap

Android7.1源码系列之一

Posted by ZhanTao on November 14, 2017

大纲:

  • 1.何为HashMap?
  • 2.数据结构&基本原理
  • 3.初始化&put&get过程

1、何为HashMap?

  • 基于哈希表(散列表)的Map接口实现
  • 保证线程安全的方法:Map map = Collections.synchronizedMap(new HashMap()); 或 ConcurrentHashMap
  • java.util.HashMap、java.util.concurrent.ConcurrentHashMap
  • http://androidxref.com/7.1.1_r6/xref/libcore/ojluni/src/main/java/java/util/HashMap.java

2、数据结构&基本原理

  • 基于数组、单链表;Key对象的散列码hashCode决定了其数组位置、通过单链表解决hash冲突(链表法、非开放地址法)。
  • transient HashMapEntry<K,V>[] table.
- 730    static class HashMapEntry<K,V> implements Map.Entry<K,V> {
- 731        final K key;
- 732        V value;
- 733        HashMapEntry<K,V> next;
- 734        int hash;

3、初始化&put&get过程

一些变量:

  • final float loadFactor = DEFAULT_LOAD_FACTOR;//负载系数,默认0.75
  • int threshold;//阈值,下次resize的门槛值,(capacity * loadFactor)
  • transient int size;//key-value数目
  • transient int modCount;//结构化修改次数

初始化:

- 274    private void inflateTable(int toSize) {
- 275        // Find a power of 2 >= toSize
- 276        int capacity = roundUpToPowerOf2(toSize);
- 277
- 278        // Android-changed: Replace usage of Math.min() here because this method is
- 279        // called from the <clinit> of runtime, at which point the native libraries
- 280        // needed by Float.* might not be loaded.
- 281        float thresholdFloat = capacity * loadFactor;
- 282        if (thresholdFloat > MAXIMUM_CAPACITY + 1) {
- 283            thresholdFloat = MAXIMUM_CAPACITY + 1;
- 284        }
- 285
- 286        threshold = (int) thresholdFloat;
- 287        table = new HashMapEntry[capacity];//初始化
- 288    }

put过程:

- 417    public V put(K key, V value) {
- 418        if (table == EMPTY_TABLE) {
- 419            inflateTable(threshold);
- 420        }
- 421        if (key == null)
- 422            return putForNullKey(value);//支持key==null的情况
- 423        int hash = sun.misc.Hashing.singleWordWangJenkinsHash(key);//获取hash值
- 424        int i = indexFor(hash, table.length);//获取索引位置
- 425        for (HashMapEntry<K,V> e = table[i]; e != null; e = e.next) {
- 426            Object k;
- 427            if (e.hash==hash && ((k = e.key) == key || key.equals(k))) {
                      //链表中,找到key,则更新value
- 428                V oldValue = e.value;
- 429                e.value = value;
- 430                e.recordAccess(this);
- 431                return oldValue;
- 432            }
- 433        }
- 434
- 435        modCount++;
- 436        addEntry(hash, key, value, i);
- 437        return null;
- 438    }

获取hash值

- 47    public static int singleWordWangJenkinsHash(Object k) {
- 48        int h = k.hashCode();
- 49
- 50        h += (h <<  15) ^ 0xffffcd7d;
- 51        h ^= (h >>> 10);
- 52        h += (h <<   3);
- 53        h ^= (h >>>  6);
- 54        h += (h <<   2) + (h << 14);
- 55        return h ^ (h >>> 16);
- 56    }

获取索引位置

- 305    static int indexFor(int h, int length) {
- 306        // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
- 307        return h & (length-1);//因为length必须是2的n次方,length - 1 = 0**011**11
- 308    }
- 806    void addEntry(int hash, K key, V value, int bucketIndex) {
- 807        if ((size >= threshold) && (null != table[bucketIndex])) {
- 808            resize(2 * table.length); //达到阈值时,扩容至2倍,后面详述
- 809            hash = (null != key) ? sun.misc.Hashing.singleWordWangJenkinsHash(key) : 0;
- 810            bucketIndex = indexFor(hash, table.length);
- 811        }
- 812
- 813        createEntry(hash, key, value, bucketIndex);
- 814    }
- 824    void createEntry(int hash, K key, V value, int bucketIndex) {
               //形成单链表,最新entry在table[]槽位,将原来的e传给最新entry.next
- 825        HashMapEntry<K,V> e = table[bucketIndex];
- 826        table[bucketIndex] = new HashMapEntry<>(hash, key, value, e);
- 827        size++;
- 828    }
- 503    void resize(int newCapacity) {
- 504        HashMapEntry[] oldTable = table;
- 505        int oldCapacity = oldTable.length;
- 506        if (oldCapacity == MAXIMUM_CAPACITY) {
- 507            threshold = Integer.MAX_VALUE;
- 508            return;
- 509        }
- 510
- 511        HashMapEntry[] newTable = new HashMapEntry[newCapacity]; //重新生成table
- 512        transfer(newTable);//搬迁数据
- 513        table = newTable;
- 514        threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
- 515    }
- 520    void transfer(HashMapEntry[] newTable) {
- 521        int newCapacity = newTable.length;
- 522        for (HashMapEntry<K,V> e : table) {
            //将链表中的entry,可能通过indexFor解决之前的冲突,从而放入新数组table的槽位中,从而提升查询速度;故loadFactor越小,查询速度越快。
- 523            while(null != e) {
- 524                HashMapEntry<K,V> next = e.next;
- 525                int i = indexFor(e.hash, newCapacity);
- 526                e.next = newTable[i];
- 527                newTable[i] = e;
- 528                e = next;
- 529            }
- 530        }
- 531    }

get过程:

- 345    public V get(Object key) {
- 346        if (key == null)
- 347            return getForNullKey();
- 348        Entry<K,V> entry = getEntry(key);
- 349
- 350        return null == entry ? null : entry.getValue();
- 351    }
- 388    final Entry<K,V> getEntry(Object key) {
- 389        if (size == 0) {
- 390            return null;
- 391        }
- 392
                //当无hash冲突时,get的时间复杂度为(1),不然只能沿着链表挨个查找
- 393        int hash = (key == null) ? 0 : sun.misc.Hashing.singleWordWangJenkinsHash(key);
- 394        for (HashMapEntry<K,V> e = table[indexFor(hash, table.length)];
- 395             e != null;
- 396             e = e.next) {
- 397            Object k;
- 398            if (e.hash == hash &&
- 399                ((k = e.key) == key || (key != null && key.equals(k))))
- 400                return e;
- 401        }
- 402        return null;
- 403    }