HashMap学习笔记一

1.Hashmap的概述:

  Hashmap是基于哈希表的Map的接口的非同步实现。此实现提供所有可选的映射操作,并且运行使用null键和null值。此类不保证映射的顺序,特别是不保证顺序的恒久不变。

2.Hashmap的数据结构:

  链表与数组的结合体

  源码:

    transient Entry[] table;

    static class Entry<K,V> implements MAp.Entry(){

      final K key;

      V value;

      Entry next

      final int hash;

      ...........

    }

   可以看到,Entry就是数组中的元素,每个Map.Entry就是一个key-value,它持有指向另一个元素的引用。这就构成了链表;

3.Hashmap的存取实现

  存储代码

  public V put(K key,V value){

    //hashmap允许null键和null值

    //当key为null的时候,就调用 putForNullKey(),将value放置在数组的第一个位置

    if(key == null)

      return putForNullKey();

    //根据key的keyCode重新计算哈希的值

    int hash = hash(key.hashcode());

    //搜索指定的值在table中的索引

    int i = indexFor(hash,table.length());

    //如果索引i处的Entry不为null,则遍历e元素的下一个元素

    for(Entry<K,V> e = table[i];e != null;e = e.next){

       Object key;

       if(hash == e.hash && (key = e.key) == key ||key.equal(key))){

         V oldValue = e.value;

         e.value = value;

         e.recordAccess(this);

         return oldValue;

       }

    }

    //操作数加一

    modCount++;

    //将key,value添加到索引处

    addEntry(hash,key,value,i);

    return null;

  }

  从上述源码中可以看出,我们往HashMap中put元素的时候,新根据key的hashCode重新计算hash值,根据哈希值获取这个元素在数组中的位置,如果数组上已经有元素则以链表的形式存放

  addEntry(int hash,K key,V value,int bucketIndex){

     //获取指定bucketIndex处的Entry

     Entry<K,V> e = table[bucketIndex];

     //将新创建的Entry放入bucketIndex索引处,新Entry指向原来的Entry

     table[bucketIndex] = new Entry<K,V>(hash,key,value,e);

     //map中key-value对象是否超过指定的数目

       if(size++ > threshold){

       //table对象扩展到原来的两倍

       resize(z*table.length());

     }

  }

  所以当存储HashMap中的key-value的时候完全没有考虑Entry中的value,仅仅根据key来计算Entry的存储位置,完全可以吧value看着key的附属。

  hash(int h)根据hashCode重新计算一次散列,此计算加入了高位算法,防止低位不变高位变化的时候发生哈希冲突。

  static hash(int h){

    h ^ = (h >>> 20) ^ (h >>> 12);

    return h ^ (h >>> 7) ^ (h >>> 4);

  }

  调用indexFor(int h,int length)来计算该吧对象保存再table数组的那个位置的索引

  public static int indexFor(int h,int length){

     return h&(length - 1);

  } 

  因为hashmap的长度总数为2的n次方,所以使用h^(length-1)算法可以对HashMap的速度进行优化。

  HashMap的构造器包含的代码

  int capacity = i;

    while(capacity < initailCapacity)

      capacity < 1;

  上述代码保证了HashMap数组的大小总是2的n次方,h&(length-1)等价于h%length。&bi%高效

  总结:

    根据put的源码分析可以知道,当程序试图将key-value放入hashmap中,会根据key的hashcode(),决定Entry的存储位置;如果key的hashcode值相同,那么他们的存储位置相同。如果key的equal()返回为true

  则新的value覆盖老的value。如果key返回为false,则形成Entry链表存储。

  

posted @ 2017-11-02 13:48  Derleser  阅读(97)  评论(0)    收藏  举报