读java.util.HashMap, HashSet源码笔记

读java.util.HashMap , HashSet 源码笔记

1、构造方法:HashMap<K, V>4个构造方法:
    1.1、用指定初始容量和指定加载因子构造一个新的空哈希表。

 1  /**
 2   * Constructs an empty <tt>HashMap</tt> with the specified initial
 3   * capacity and load factor.
 4   *
 5   *  @param   initialCapacity the initial capacity
 6   *  @param   loadFactor      the load factor
 7   *  @throws  IllegalArgumentException if the initial capacity is negative
 8   *         or the load factor is nonpositive
 9    */
10  public  HashMap( int  initialCapacity,  float  loadFactor) {
11       if  (initialCapacity  <   0 )
12           throw   new  IllegalArgumentException( " Illegal initial capacity:  "   +
13                                             initialCapacity);
14       if  (initialCapacity  >  MAXIMUM_CAPACITY)
15          initialCapacity  =  MAXIMUM_CAPACITY;
16       if  (loadFactor  <=   0   ||  Float.isNaN(loadFactor))
17           throw   new  IllegalArgumentException( " Illegal load factor:  "   +
18                                             loadFactor);
19 
20       //  Find a power of 2 >= initialCapacity
21       int  capacity  =   1 ;
22       while  (capacity  <  initialCapacity)
23          capacity  <<=   1 ;
24 
25       this .loadFactor  =  loadFactor;
26      threshold  =  ( int )(capacity  *  loadFactor);
27      table  =   new  Entry[capacity];
28      init();
29  }
可以看出HashMap1)无容量限制,但是其Entry[] table是有长度限制的,最大长度为2^30;2)Entry[] table的长度始终为2的指数幂。
Map < String, String >  map  =   new  HashMap( 5 0.64f )
来创建一个map对象,则可以看出map的容量为8,而不是5;在该map的容量大于0.64*8时候,开始扩容。扩容方式在后面讲。这里的init()方法在JDK_1.6.0_16中是一个空方法。
    1.2、public HashMap(int initialCapacity)同
HashMap(initialCapacity,  0.75f );
     1.3、public HashMap()
HashMap( 16 0.75f );
    1.4、构造一个指定Map具有相同关系映射关系的新HashMap<K, V>
1  public  HashMap(Map <?   extends  K,  ?   extends  V >  m) {
2       this (Math.max(( int ) (m.size()  /  DEFAULT_LOAD_FACTOR)  +   1 ,
3                    DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
4      putAllForCreate(m);
5  }


2、put(K key, V value)
    2.1、key == null则
        取table[0]并对table[0].next进行遍历,如果找到为null的key把value替换,并将原来的value返回;
        如果没有找到则在Entry<K, V> e = table[0];table[0] = new Entry(0, null, value, e);
        其中Entry的参数意义分别为:hash(key.hashCode());key;value;Entry<K, V>
    2.2、key != null则
        1)计算key的hash;hash = hash(key.hashCode());
        2)找到该key位于Entry<K, V>table的下标index
        3)取Entry<K,V> e = table[index];对e.next进行遍历查找key,查找方式为:
(Object k  =  e.key)  ==  key  ||  (key  !=   null   &&  key.equals(k);
            3.1)找到,则把value替换;并将原来的value返回。
            3.2)没有找到,Entry<K, V> e = table[hash];table[hash] = new Entry<K,V>(hash, key, value, e)
   
    可以看出,如果有相同的hash,HashMap的存储方式为:链表存储的。
    
3、get(Object key)
    和put<K k, V v>的查找方式一样。

4、remove(Object key)

     也是先计算hash,然后找到table的下标,对该下标的Entry<K, V>.next进行遍历;查找方式为:
 e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))
    找到则把table[index] = table[index].next;

5、计算hash的处理。hash(int h)JDK上的解释是为了尽可能的避免key的hashCode的冲突,
        
但是为什么要这么计算hash目前看不懂

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

6、查找下标的操作:indexFor(int h, int length) Sun JDK采取位运算,而不是采用整除,这样效率高
static   int  indexFor( int  h,  int  length) {
    
return  h  &  (length - 1 );
}

PS:HashSet是基于HashMap实现的,HashSet.add(k)相当于HashMap.put(k, new Object());

 

你可能感兴趣的:(读java.util.HashMap, HashSet源码笔记)