zoukankan      html  css  js  c++  java
  • 数据结构(集合)学习之Map(一)

    集合

    框架关系图:

     补充:HashTable父类是Dictionary,不是AbstractMap。

    Map:

     Map(接口)和Collection都属于集合,但是Map不是Collection的子类或者子接口。而且Map比较特殊:它是以<key,value>键值对的方式来存储数据,其中key不能重复,且一个key最多只对应一个value。

    Map在面试中常问的三个子类:HashMap、HashTable、TreeMap。

    HashMap:

     基于哈希表的实现的Map接口, 该实现提供了所有可选的映射操作,并允许null的key和null的value。

    在JDK1.8以前,HashMap底层是:"链表+数组"结构;在JDK1.8时,对HashMap底层进行优化,成了:数组+链表+红黑树。

    JDK1.6:初始容量为16,加载因子为0.75,底层是Entry数组加链表结构:

      1 //初始容量
      2     static final int DEFAULT_INITIAL_CAPACITY = 16;
      3 //加载因子
      4     static final float DEFAULT_LOAD_FACTOR = 0.75f;
      5 //存储容器-数组
      6     transient Entry[] table;
      7 //静态内部类    
      8    static class Entry<K,V> implements Map.Entry<K,V> {
      9         final K key;
     10         V value;
     11         Entry<K,V> next;//把key和value转换成数组中的Entry对象
     12         final int hash;
     13 
     14         /**
     15          * Creates new entry.
     16          */
     17         Entry(int h, K k, V v, Entry<K,V> n) {
     18             value = v;
     19             next = n;
     20             key = k;
     21             hash = h;
     22         }
     23 
     24         public final K getKey() {
     25             return key;
     26         }
     27 
     28         public final V getValue() {
     29             return value;
     30         }
     31 
     32         public final V setValue(V newValue) {
     33         V oldValue = value;
     34             value = newValue;
     35             return oldValue;
     36         }
     37 
     38         public final boolean equals(Object o) {
     39             if (!(o instanceof Map.Entry))
     40                 return false;
     41             Map.Entry e = (Map.Entry)o;
     42             Object k1 = getKey();
     43             Object k2 = e.getKey();
     44             if (k1 == k2 || (k1 != null && k1.equals(k2))) {
     45                 Object v1 = getValue();
     46                 Object v2 = e.getValue();
     47                 if (v1 == v2 || (v1 != null && v1.equals(v2)))
     48                     return true;
     49             }
     50             return false;
     51         }
     52 
     53         public final int hashCode() {
     54             return (key==null   ? 0 : key.hashCode()) ^
     55                    (value==null ? 0 : value.hashCode());
     56         }
     57 
     58         public final String toString() {
     59             return getKey() + "=" + getValue();
     60         }
     61 
     62         void recordAccess(HashMap<K,V> m) {
     63         }
     64 
     65         void recordRemoval(HashMap<K,V> m) {
     66         }
     67     }
     68 //Put方法
     69     public V put(K key, V value) {
     70         if (key == null)
     71             return putForNullKey(value);//hashmap可以存key==null
     72         int hash = hash(key.hashCode());//根据key的hashcode计算一个哈希数
     73         int i = indexFor(hash, table.length);//根据计算的哈希数获取数组的坐标
     74         for (Entry<K,V> e = table[i]; e != null; e = e.next) {//hashmap不允许重复,如果key重复了,把新的value替换老的value
     75             Object k;
     76             if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//
     77                 V oldValue = e.value;
     78                 e.value = value;
     79                 e.recordAccess(this);
     80                 return oldValue;
     81             }
     82         }
     83 
     84         modCount++;
     85         addEntry(hash, key, value, i);//处理好以后把hash,key,value,index添加到数组中去
     86         return null;
     87     }
     88 //针对key=null的方法
     89     private V putForNullKey(V value) {
     90         for (Entry<K,V> e = table[0]; e != null; e = e.next) {
     91             if (e.key == null) {
     92                 V oldValue = e.value;
     93                 e.value = value;
     94                 e.recordAccess(this);
     95                 return oldValue;
     96             }
     97         }
     98         modCount++;
     99         addEntry(0, null, value, 0);
    100         return null;
    101     }
    102 //获取哈希数
    103     static int hash(int h) {
    104         // This function ensures that hashCodes that differ only by
    105         // constant multiples at each bit position have a bounded
    106         // number of collisions (approximately 8 at default load factor).
    107         h ^= (h >>> 20) ^ (h >>> 12);
    108         return h ^ (h >>> 7) ^ (h >>> 4);
    109     }
    110 //获取数组坐标
    111     static int indexFor(int h, int length) {
    112         return h & (length-1);
    113     }
    114 //添加元素的方法
    115     void addEntry(int hash, K key, V value, int bucketIndex) {
    116     Entry<K,V> e = table[bucketIndex];//如果index相同了(哈希碰撞),把原来的值给一个新的Entry对象
    117     //然后把新来的值存在数组中,老值作为新值的下标(next对象),在此也体现了hashmap的“链式结构”
    118         table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
    119         if (size++ >= threshold)
    120             resize(2 * table.length);//如果数值超容了,进行扩容:数组的长度*2(默认初始容量16,所以为16*2=32)
    121     }
    122 //扩容方法
    123     void resize(int newCapacity) {//2倍长度作为参数传入
    124         Entry[] oldTable = table;
    125         int oldCapacity = oldTable.length;
    126         if (oldCapacity == MAXIMUM_CAPACITY) {
    127             threshold = Integer.MAX_VALUE;
    128             return;
    129         }
    130 
    131         Entry[] newTable = new Entry[newCapacity];//新建数组
    132         transfer(newTable);//数组值转换的方法
    133         table = newTable;
    134         threshold = (int)(newCapacity * loadFactor);
    135     }
    136 //数组值转换的方法
    137     void transfer(Entry[] newTable) {
    138         Entry[] src = table;
    139         int newCapacity = newTable.length;
    140         for (int j = 0; j < src.length; j++) {
    141             Entry<K,V> e = src[j];
    142             if (e != null) {
    143                 src[j] = null;
    144                 do {//此处为复制的过程
    145                     Entry<K,V> next = e.next;
    146                     int i = indexFor(e.hash, newCapacity);
    147                     e.next = newTable[i];
    148                     newTable[i] = e;
    149                     e = next;
    150                 } while (e != null);
    151             }
    152         }
    153     }
    154 //Get方法
    155     public V get(Object key) {
    156         if (key == null)
    157             return getForNullKey();//遍历,获取到key==null的值
    158         int hash = hash(key.hashCode());//然后根据key获取哈希值
    159         for (Entry<K,V> e = table[indexFor(hash, table.length)];//然后获取坐标得到Entry对象
    160              e != null;
    161              e = e.next) {//从第一个开始遍历,如果不是,把Entry对象的下标给Entry然后比较
    162             Object k;
    163             if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
    164                 return e.value;//当哈希值和key都相等的时候,把value返回去
    165         }
    166         return null;
    167     }
    168 //key等于null获取值
    169     private V getForNullKey() {
    170         for (Entry<K,V> e = table[0]; e != null; e = e.next) {
    171             if (e.key == null)
    172                 return e.value;
    173         }
    174         return null;
    175     }
    176 //Clear方法
    177     public void clear() {
    178         modCount++;
    179         Entry[] tab = table;
    180         for (int i = 0; i < tab.length; i++)//遍历数组,把值清空,把size置为0
    181             tab[i] = null;
    182         size = 0;
    183     }
    184 //entrySet​方法:获取到数组中Entry对象的Set集合
    185     private transient Set<Map.Entry<K,V>> entrySet = null;
    186     
    187     public Set<Map.Entry<K,V>> entrySet() {
    188     return entrySet0();
    189     }
    190     private Set<Map.Entry<K,V>> entrySet0() {
    191         Set<Map.Entry<K,V>> es = entrySet;
    192         return es != null ? es : (entrySet = new EntrySet());
    193     }
    194 //原理就是迭代map中的Entry对象
    195     private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
    196         public Iterator<Map.Entry<K,V>> iterator() {
    197             return newEntryIterator();
    198         }
    199         public boolean contains(Object o) {
    200             if (!(o instanceof Map.Entry))
    201                 return false;
    202             Map.Entry<K,V> e = (Map.Entry<K,V>) o;
    203             Entry<K,V> candidate = getEntry(e.getKey());
    204             return candidate != null && candidate.equals(e);
    205         }
    206         public boolean remove(Object o) {
    207             return removeMapping(o) != null;
    208         }
    209         public int size() {
    210             return size;
    211         }
    212         public void clear() {
    213             HashMap.this.clear();
    214         }
    215     }
    216         final Entry<K,V> nextEntry() {
    217             if (modCount != expectedModCount)
    218                 throw new ConcurrentModificationException();
    219             Entry<K,V> e = next;
    220             if (e == null)
    221                 throw new NoSuchElementException();
    222 
    223             if ((next = e.next) == null) {
    224                 Entry[] t = table;
    225                 while (index < t.length && (next = t[index++]) == null) ;
    226             }
    227         current = e;
    228             return e;
    229         }
    230 //keySet​方法
    231     public Set<K> keySet() {
    232         Set<K> ks = keySet;
    233         return (ks != null ? ks : (keySet = new KeySet()));
    234     }
    235 //原理也是通过迭代器,迭代Entry对象,然后获取key
    236     private final class KeySet extends AbstractSet<K> {
    237         public Iterator<K> iterator() {
    238             return newKeyIterator();
    239         }
    240         public int size() {
    241             return size;
    242         }
    243         public boolean contains(Object o) {
    244             return containsKey(o);
    245         }
    246         public boolean remove(Object o) {
    247             return HashMap.this.removeEntryForKey(o) != null;
    248         }
    249         public void clear() {
    250             HashMap.this.clear();
    251         }
    252     }
    253 
    254     private final class KeyIterator extends HashIterator<K> {
    255         public K next() {
    256             return nextEntry().getKey();
    257         }
    258     }
    259 //remove方法
    260     public V remove(Object key) {
    261         Entry<K,V> e = removeEntryForKey(key);
    262         return (e == null ? null : e.value);
    263     }
    264     final Entry<K,V> removeEntryForKey(Object key) {
    265         int hash = (key == null) ? 0 : hash(key.hashCode());
    266         int i = indexFor(hash, table.length);
    267         Entry<K,V> prev = table[i];
    268         Entry<K,V> e = prev;
    269 
    270         while (e != null) {//用while循环,当哈希值和key都相等的时候把值得next赋值给现在位置的值
    271             Entry<K,V> next = e.next;
    272             Object k;
    273             if (e.hash == hash &&
    274                 ((k = e.key) == key || (key != null && key.equals(k)))) {
    275                 modCount++;
    276                 size--;
    277                 if (prev == e)
    278                     table[i] = next;
    279                 else
    280                     prev.next = next;
    281                 e.recordRemoval(this);
    282                 return e;
    283             }
    284             prev = e;
    285             e = next;
    286         }
    287 
    288         return e;
    289     }
    290 //size方法和isEmpty方法
    291     transient int size;//和put以及remove方法有关系,增加就++,删除就--
    292     public int size() {
    293         return size;
    294     }
    295     public boolean isEmpty() {
    296         return size == 0;
    297     }
    298 //contains方法
    299     public boolean contains(Object o) {
    300         return containsKey(o);
    301     }
    302     public boolean containsKey(Object key) {
    303         return getEntry(key) != null;
    304     }
    305     final Entry<K,V> getEntry(Object key) {
    306         if (size == 0) {
    307             return null;
    308         }
    309 
    310         int hash = (key == null) ? 0 : hash(key);
    311         for (Entry<K,V> e = table[indexFor(hash, table.length)];
    312              e != null;
    313              e = e.next) {
    314             Object k;
    315             if (e.hash == hash &&
    316                 ((k = e.key) == key || (key != null && key.equals(k))))
    317                 return e;
    318         }
    319         return null;
    320     }
    View Code

    补充1:

    哈希表(Hash table,采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表(Hash table)),是根据关键码值(Key value)而直接进行访问的数据结构,也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。
    记录的存储位置=f(关键字),被称为散列函数,又称为哈希(Hash函数),

    补充二:

    两个对象相等,hashCode一定相同,但是两个对象的HashCode相同,这两个对象不一定相等。

    JDK1.7源码(和1.6的对比):

      1 //对比一:1.7默认初始容量用了位移计算 
      2    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
      3 //加载因子
      4     static final float DEFAULT_LOAD_FACTOR = 0.75f;
      5 //存储容器-数组
      6     static final Entry<?,?>[] EMPTY_TABLE = {};
      7     
      8     transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
      9 //静态内部类    
     10     static class Entry<K,V> implements Map.Entry<K,V> {
     11         final K key;
     12         V value;
     13         Entry<K,V> next;
     14         int hash;
     15 
     16         /**
     17          * Creates new entry.
     18          */
     19         Entry(int h, K k, V v, Entry<K,V> n) {
     20             value = v;
     21             next = n;
     22             key = k;
     23             hash = h;
     24         }
     25 
     26         public final K getKey() {
     27             return key;
     28         }
     29 
     30         public final V getValue() {
     31             return value;
     32         }
     33 
     34         public final V setValue(V newValue) {
     35             V oldValue = value;
     36             value = newValue;
     37             return oldValue;
     38         }
     39 
     40         public final boolean equals(Object o) {
     41             if (!(o instanceof Map.Entry))
     42                 return false;
     43             Map.Entry e = (Map.Entry)o;
     44             Object k1 = getKey();
     45             Object k2 = e.getKey();
     46             if (k1 == k2 || (k1 != null && k1.equals(k2))) {
     47                 Object v1 = getValue();
     48                 Object v2 = e.getValue();
     49                 if (v1 == v2 || (v1 != null && v1.equals(v2)))
     50                     return true;
     51             }
     52             return false;
     53         }
     54 
     55         public final int hashCode() {
     56             return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
     57         }
     58 
     59         public final String toString() {
     60             return getKey() + "=" + getValue();
     61         }
     62 
     63         /**
     64          * This method is invoked whenever the value in an entry is
     65          * overwritten by an invocation of put(k,v) for a key k that's already
     66          * in the HashMap.
     67          */
     68         void recordAccess(HashMap<K,V> m) {
     69         }
     70 
     71         /**
     72          * This method is invoked whenever the entry is
     73          * removed from the table.
     74          */
     75         void recordRemoval(HashMap<K,V> m) {
     76         }
     77     }
     78 //Put方法
     79     public V put(K key, V value) {
     80         if (table == EMPTY_TABLE) {//此出多了一个数组初始化的方法
     81             inflateTable(threshold);
     82         }
     83         if (key == null)
     84             return putForNullKey(value);
     85         int hash = hash(key);
     86         int i = indexFor(hash, table.length);
     87         for (Entry<K,V> e = table[i]; e != null; e = e.next) {
     88             Object k;
     89             if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
     90                 V oldValue = e.value;
     91                 e.value = value;
     92                 e.recordAccess(this);
     93                 return oldValue;
     94             }
     95         }
     96 
     97         modCount++;
     98         addEntry(hash, key, value, i);
     99         return null;
    100     }
    101 //初始化数组
    102     private void inflateTable(int toSize) {
    103        
    104         int capacity = roundUpToPowerOf2(toSize); // 此处把传入的数组容量向上转换为2的n次幂的数值
    105 
    106         threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
    107         table = new Entry[capacity];
    108         initHashSeedAsNeeded(capacity);
    109     }
    110     final boolean initHashSeedAsNeeded(int capacity) {
    111         boolean currentAltHashing = hashSeed != 0;
    112         boolean useAltHashing = sun.misc.VM.isBooted() &&
    113                 (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
    114         boolean switching = currentAltHashing ^ useAltHashing;
    115         if (switching) {
    116             hashSeed = useAltHashing
    117                 ? sun.misc.Hashing.randomHashSeed(this)
    118                 : 0;
    119         }
    120         return switching;
    121     }
    122 //针对key=null的方法
    123     private V putForNullKey(V value) {
    124         for (Entry<K,V> e = table[0]; e != null; e = e.next) {
    125             if (e.key == null) {
    126                 V oldValue = e.value;
    127                 e.value = value;
    128                 e.recordAccess(this);
    129                 return oldValue;
    130             }
    131         }
    132         modCount++;
    133         addEntry(0, null, value, 0);
    134         return null;
    135     }
    136 //获取哈希数
    137     final int hash(Object k) {
    138         int h = hashSeed;
    139         if (0 != h && k instanceof String) {
    140             return sun.misc.Hashing.stringHash32((String) k);
    141         }
    142 
    143         h ^= k.hashCode();
    144 
    145         h ^= (h >>> 20) ^ (h >>> 12);
    146         return h ^ (h >>> 7) ^ (h >>> 4);
    147     }
    148 //获取数组坐标
    149     static int indexFor(int h, int length) {
    150         // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
    151         return h & (length-1);
    152     }
    153 //添加元素的方法
    154     void addEntry(int hash, K key, V value, int bucketIndex) {
    155         if ((size >= threshold) && (null != table[bucketIndex])) {//1.7这里先进行是否需要扩容的判断
    156             resize(2 * table.length);
    157             hash = (null != key) ? hash(key) : 0;
    158             bucketIndex = indexFor(hash, table.length);
    159         }
    160 
    161         createEntry(hash, key, value, bucketIndex);
    162     }
    163 //扩容方法
    164     void resize(int newCapacity) {
    165         Entry[] oldTable = table;
    166         int oldCapacity = oldTable.length;
    167         if (oldCapacity == MAXIMUM_CAPACITY) {
    168             threshold = Integer.MAX_VALUE;
    169             return;
    170         }
    171 
    172         Entry[] newTable = new Entry[newCapacity];
    173         transfer(newTable, initHashSeedAsNeeded(newCapacity));
    174         table = newTable;
    175         threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
    176     }
    177 //数组值转换的方法
    178     void transfer(Entry[] newTable, boolean rehash) {
    179         int newCapacity = newTable.length;
    180         for (Entry<K,V> e : table) {
    181             while(null != e) {
    182                 Entry<K,V> next = e.next;
    183                 if (rehash) {
    184                     e.hash = null == e.key ? 0 : hash(e.key);
    185                 }
    186                 int i = indexFor(e.hash, newCapacity);
    187                 e.next = newTable[i];
    188                 newTable[i] = e;
    189                 e = next;
    190             }
    191         }
    192     }
    193 //添加元素的方法
    194     void createEntry(int hash, K key, V value, int bucketIndex) {
    195         Entry<K,V> e = table[bucketIndex];
    196         table[bucketIndex] = new Entry<>(hash, key, value, e);
    197         size++;
    198     }
    199 //Get方法
    200     public V get(Object key) {
    201         if (key == null)
    202             return getForNullKey();
    203         Entry<K,V> entry = getEntry(key);
    204 
    205         return null == entry ? null : entry.getValue();
    206     }
    207 //key等于null获取值
    208     private V getForNullKey() {
    209         if (size == 0) {//1.7在此处又多了个判断数组是否为空的情况
    210             return null;
    211         }
    212         for (Entry<K,V> e = table[0]; e != null; e = e.next) {
    213             if (e.key == null)
    214                 return e.value;
    215         }
    216         return null;
    217     }
    218 //Clear方法    
    219     public void clear() {
    220         modCount++;
    221         Arrays.fill(table, null);//1,7此处调用了Arrays中的方法,不过原理还是一样的
    222         size = 0;
    223     }
    224 
    225     public static void fill(Object[] a, Object val) {
    226         for (int i = 0, len = a.length; i < len; i++)
    227             a[i] = val;
    228     }
    229 //entrySet​方法:获取到数组中Entry对象的Set集合
    230     private transient Set<Map.Entry<K,V>> entrySet = null;
    231 
    232     public Set<Map.Entry<K,V>> entrySet() {
    233         return entrySet0();
    234     }
    235 
    236     private Set<Map.Entry<K,V>> entrySet0() {
    237         Set<Map.Entry<K,V>> es = entrySet;
    238         return es != null ? es : (entrySet = new EntrySet());
    239     }
    240 //原理就是迭代map中的Entry对象
    241     private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
    242         public Iterator<Map.Entry<K,V>> iterator() {
    243             return newEntryIterator();
    244         }
    245         public boolean contains(Object o) {
    246             if (!(o instanceof Map.Entry))
    247                 return false;
    248             Map.Entry<K,V> e = (Map.Entry<K,V>) o;
    249             Entry<K,V> candidate = getEntry(e.getKey());
    250             return candidate != null && candidate.equals(e);
    251         }
    252         public boolean remove(Object o) {
    253             return removeMapping(o) != null;
    254         }
    255         public int size() {
    256             return size;
    257         }
    258         public void clear() {
    259             HashMap.this.clear();
    260         }
    261     }
    262 //keySet​方法
    263     public Set<K> keySet() {
    264         Set<K> ks = keySet;
    265         return (ks != null ? ks : (keySet = new KeySet()));
    266     }
    267 //原理也是通过迭代器,迭代Entry对象,然后获取key
    268     private final class KeySet extends AbstractSet<K> {
    269         public Iterator<K> iterator() {
    270             return newKeyIterator();
    271         }
    272         public int size() {
    273             return size;
    274         }
    275         public boolean contains(Object o) {
    276             return containsKey(o);
    277         }
    278         public boolean remove(Object o) {
    279             return HashMap.this.removeEntryForKey(o) != null;
    280         }
    281         public void clear() {
    282             HashMap.this.clear();
    283         }
    284     }
    285 //remove方法
    286     public V remove(Object key) {
    287         Entry<K,V> e = removeEntryForKey(key);
    288         return (e == null ? null : e.value);
    289     }
    290 
    291     final Entry<K,V> removeEntryForKey(Object key) {
    292         if (size == 0) {
    293             return null;
    294         }
    295         int hash = (key == null) ? 0 : hash(key);
    296         int i = indexFor(hash, table.length);
    297         Entry<K,V> prev = table[i];
    298         Entry<K,V> e = prev;
    299 
    300         while (e != null) {
    301             Entry<K,V> next = e.next;
    302             Object k;
    303             if (e.hash == hash &&
    304                 ((k = e.key) == key || (key != null && key.equals(k)))) {
    305                 modCount++;
    306                 size--;
    307                 if (prev == e)
    308                     table[i] = next;
    309                 else
    310                     prev.next = next;
    311                 e.recordRemoval(this);
    312                 return e;
    313             }
    314             prev = e;
    315             e = next;
    316         }
    317 
    318         return e;
    319     }
    320 //size方法、isEmpty方法、contains方法
    321     public int size() {
    322         return size;
    323     }
    324     public boolean isEmpty() {
    325         return size == 0;
    326     }
    327 
    328     public boolean contains(Object o) {
    329         return containsKey(o);
    330     }
    331     public boolean containsKey(Object key) {
    332         return getEntry(key) != null;
    333     }
    334     final Entry<K,V> getEntry(Object key) {
    335         if (size == 0) {
    336             return null;
    337         }
    338 
    339         int hash = (key == null) ? 0 : hash(key);
    340         for (Entry<K,V> e = table[indexFor(hash, table.length)];
    341              e != null;
    342              e = e.next) {
    343             Object k;
    344             if (e.hash == hash &&
    345                 ((k = e.key) == key || (key != null && key.equals(k))))
    346                 return e;
    347         }
    348         return null;
    349     }
    View Code

    对比可以看出,1.6和1.7重要方法的原理基本没变,1.7在部分方法上做了一点小的优化,还有就是从1.7开始,创建无参hashmap时不直接生成数组了,采用懒加载的方式,在用的时候再初始化。

    1.6无参构造函数:

    1     public HashMap() {
    2         this.loadFactor = DEFAULT_LOAD_FACTOR;
    3         threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
    4         table = new Entry[DEFAULT_INITIAL_CAPACITY];
    5         init();
    6     }

    1.7无参构造函数(在Put方法中,判断table等于空的时候再创建):

    1     public HashMap() {
    2         this.loadFactor = DEFAULT_LOAD_FACTOR; 
    3     }

    HashMap1.8:初始容量为16,加载因子为0.75,底层是Node数组+链表+红黑树:

      1 //初始容量
      2     static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
      3 //加载因子
      4     static final float DEFAULT_LOAD_FACTOR = 0.75f;
      5 //转为红黑树的阈(yu)值
      6     static final int TREEIFY_THRESHOLD = 8;
      7 //从红黑树转换为链表的阈值(扩容会重新计算一次数据长度)
      8     static final int UNTREEIFY_THRESHOLD = 6;
      9 //默认红黑树的容量
     10     static final int MIN_TREEIFY_CAPACITY = 64;
     11 //存储容器-数组,由1.7的Entry<K,V>[]数组变为了Node<K,V>[]
     12 
     13    transient Node<K,V>[] table;
     14 
     15    static class Node<K,V> implements Map.Entry<K,V> {
     16         final int hash;
     17         final K key;
     18         V value;
     19         Node<K,V> next;
     20 
     21         Node(int hash, K key, V value, Node<K,V> next) {
     22             this.hash = hash;
     23             this.key = key;
     24             this.value = value;
     25             this.next = next;
     26         }
     27 
     28         public final K getKey()        { return key; }
     29         public final V getValue()      { return value; }
     30         public final String toString() { return key + "=" + value; }
     31 
     32         public final int hashCode() {
     33             return Objects.hashCode(key) ^ Objects.hashCode(value);
     34         }
     35 
     36         public final V setValue(V newValue) {
     37             V oldValue = value;
     38             value = newValue;
     39             return oldValue;
     40         }
     41 
     42         public final boolean equals(Object o) {
     43             if (o == this)
     44                 return true;
     45             if (o instanceof Map.Entry) {
     46                 Map.Entry<?,?> e = (Map.Entry<?,?>)o;
     47                 if (Objects.equals(key, e.getKey()) &&
     48                     Objects.equals(value, e.getValue()))
     49                     return true;
     50             }
     51             return false;
     52         }
     53     }
     54 //Put方法
     55     public V put(K key, V value) {
     56         return putVal(hash(key), key, value, false, true);
     57     }
     58 
     59     final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
     60                    boolean evict) {
     61         Node<K,V>[] tab; Node<K,V> p; int n, i;
     62         if ((tab = table) == null || (n = tab.length) == 0)
     63             n = (tab = resize()).length;//首先还是先判断数组是否为空的,是的话进行初始化
     64         if ((p = tab[i = (n - 1) & hash]) == null)//如果数组该位置为空,则把key,value传入该位置
     65             tab[i] = newNode(hash, key, value, null);
     66         else {//走到这说明发生了哈希碰撞,计算的key的哈希值相同
     67             Node<K,V> e; K k;
     68             if (p.hash == hash &&
     69                 ((k = p.key) == key || (key != null && key.equals(k))))//先比较数据是否重复,重复的话就新值替换旧值
     70                 e = p;
     71             else if (p instanceof TreeNode)//判断该对象是不是红黑树的元素,是的话直接存入红黑树
     72                 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
     73             else {
     74                 for (int binCount = 0; ; ++binCount) {//遍历链表上的元素
     75                     if ((e = p.next) == null) {
     76                         p.next = newNode(hash, key, value, null);
     77                         if (binCount >= TREEIFY_THRESHOLD - 1) // 如果数量达到临界点,则转换为红黑树
     78                             treeifyBin(tab, hash);//转换方法
     79                         break;
     80                     }
     81                     if (e.hash == hash &&
     82                         ((k = e.key) == key || (key != null && key.equals(k))))
     83                         break;
     84                     p = e;//e其实是p.next,此处体现1.8的尾插法
     85                 }
     86             }
     87             if (e != null) { // 此处作用为,当key相同时,新value替换老的value,并将oleValue返回出去
     88                 V oldValue = e.value;
     89                 if (!onlyIfAbsent || oldValue == null)
     90                     e.value = value;
     91                 afterNodeAccess(e);
     92                 return oldValue;
     93             }
     94         }
     95         ++modCount;
     96         if (++size > threshold)//如果数组大于初始量*加载因子,则进行扩容
     97             resize();
     98         afterNodeInsertion(evict);
     99         return null;
    100     }
    101 //空数组初始化方法
    102     final Node<K,V>[] resize() {
    103         Node<K,V>[] oldTab = table;
    104         int oldCap = (oldTab == null) ? 0 : oldTab.length;
    105         int oldThr = threshold;
    106         int newCap, newThr = 0;
    107         if (oldCap > 0) {
    108             if (oldCap >= MAXIMUM_CAPACITY) {
    109                 threshold = Integer.MAX_VALUE;
    110                 return oldTab;
    111             }
    112             else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
    113                      oldCap >= DEFAULT_INITIAL_CAPACITY)
    114                 newThr = oldThr << 1; // double threshold
    115         }
    116         else if (oldThr > 0) // initial capacity was placed in threshold
    117             newCap = oldThr;
    118         else {               // zero initial threshold signifies using defaults
    119             newCap = DEFAULT_INITIAL_CAPACITY;
    120             newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    121         }
    122         if (newThr == 0) {
    123             float ft = (float)newCap * loadFactor;
    124             newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
    125                       (int)ft : Integer.MAX_VALUE);
    126         }
    127         threshold = newThr;
    128         @SuppressWarnings({"rawtypes","unchecked"})
    129             Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
    130         table = newTab;
    131         if (oldTab != null) {
    132             for (int j = 0; j < oldCap; ++j) {
    133                 Node<K,V> e;
    134                 if ((e = oldTab[j]) != null) {
    135                     oldTab[j] = null;
    136                     if (e.next == null)
    137                         newTab[e.hash & (newCap - 1)] = e;
    138                     else if (e instanceof TreeNode)
    139                         ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
    140                     else { // preserve order
    141                         Node<K,V> loHead = null, loTail = null;
    142                         Node<K,V> hiHead = null, hiTail = null;
    143                         Node<K,V> next;
    144                         do {
    145                             next = e.next;
    146                             if ((e.hash & oldCap) == 0) {
    147                                 if (loTail == null)
    148                                     loHead = e;
    149                                 else
    150                                     loTail.next = e;
    151                                 loTail = e;
    152                             }
    153                             else {
    154                                 if (hiTail == null)
    155                                     hiHead = e;
    156                                 else
    157                                     hiTail.next = e;
    158                                 hiTail = e;
    159                             }
    160                         } while ((e = next) != null);
    161                         if (loTail != null) {
    162                             loTail.next = null;
    163                             newTab[j] = loHead;
    164                         }
    165                         if (hiTail != null) {
    166                             hiTail.next = null;
    167                             newTab[j + oldCap] = hiHead;
    168                         }
    169                     }
    170                 }
    171             }
    172         }
    173         return newTab;
    174     }
    175 //存入红黑树
    176         final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
    177                                        int h, K k, V v) {
    178             Class<?> kc = null;
    179             boolean searched = false;
    180             TreeNode<K,V> root = (parent != null) ? root() : this;
    181             for (TreeNode<K,V> p = root;;) {
    182                 int dir, ph; K pk;
    183                 if ((ph = p.hash) > h)
    184                     dir = -1;
    185                 else if (ph < h)
    186                     dir = 1;
    187                 else if ((pk = p.key) == k || (k != null && k.equals(pk)))
    188                     return p;
    189                 else if ((kc == null &&
    190                           (kc = comparableClassFor(k)) == null) ||
    191                          (dir = compareComparables(kc, k, pk)) == 0) {
    192                     if (!searched) {
    193                         TreeNode<K,V> q, ch;
    194                         searched = true;
    195                         if (((ch = p.left) != null &&
    196                              (q = ch.find(h, k, kc)) != null) ||
    197                             ((ch = p.right) != null &&
    198                              (q = ch.find(h, k, kc)) != null))
    199                             return q;
    200                     }
    201                     dir = tieBreakOrder(k, pk);
    202                 }
    203 
    204                 TreeNode<K,V> xp = p;
    205                 if ((p = (dir <= 0) ? p.left : p.right) == null) {
    206                     Node<K,V> xpn = xp.next;
    207                     TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
    208                     if (dir <= 0)
    209                         xp.left = x;
    210                     else
    211                         xp.right = x;
    212                     xp.next = x;
    213                     x.parent = x.prev = xp;
    214                     if (xpn != null)
    215                         ((TreeNode<K,V>)xpn).prev = x;
    216                     moveRootToFront(tab, balanceInsertion(root, x));
    217                     return null;
    218                 }
    219             }
    220         }
    221 //转换为红黑树
    222     final void treeifyBin(Node<K,V>[] tab, int hash) {
    223         int n, index; Node<K,V> e;
    224         if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
    225             resize();
    226         else if ((e = tab[index = (n - 1) & hash]) != null) {
    227             TreeNode<K,V> hd = null, tl = null;
    228             do {
    229                 TreeNode<K,V> p = replacementTreeNode(e, null);
    230                 if (tl == null)
    231                     hd = p;
    232                 else {
    233                     p.prev = tl;
    234                     tl.next = p;
    235                 }
    236                 tl = p;
    237             } while ((e = e.next) != null);
    238             if ((tab[index] = hd) != null)
    239                 hd.treeify(tab);
    240         }
    241     }
    242 //扩容方法
    243     final Node<K,V>[] resize() {
    244         Node<K,V>[] oldTab = table;
    245         int oldCap = (oldTab == null) ? 0 : oldTab.length;
    246         int oldThr = threshold;
    247         int newCap, newThr = 0;
    248         if (oldCap > 0) {
    249             if (oldCap >= MAXIMUM_CAPACITY) {
    250                 threshold = Integer.MAX_VALUE;
    251                 return oldTab;
    252             }
    253             else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
    254                      oldCap >= DEFAULT_INITIAL_CAPACITY)
    255                 newThr = oldThr << 1; // double threshold
    256         }
    257         else if (oldThr > 0) // initial capacity was placed in threshold
    258             newCap = oldThr;
    259         else {               // zero initial threshold signifies using defaults
    260             newCap = DEFAULT_INITIAL_CAPACITY;
    261             newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    262         }
    263         if (newThr == 0) {
    264             float ft = (float)newCap * loadFactor;
    265             newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
    266                       (int)ft : Integer.MAX_VALUE);
    267         }
    268         threshold = newThr;
    269         @SuppressWarnings({"rawtypes","unchecked"})
    270             Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
    271         table = newTab;
    272         if (oldTab != null) {
    273             for (int j = 0; j < oldCap; ++j) {
    274                 Node<K,V> e;
    275                 if ((e = oldTab[j]) != null) {
    276                     oldTab[j] = null;
    277                     if (e.next == null)
    278                         newTab[e.hash & (newCap - 1)] = e;
    279                     else if (e instanceof TreeNode)
    280                         ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
    281                     else { // preserve order
    282                         Node<K,V> loHead = null, loTail = null;
    283                         Node<K,V> hiHead = null, hiTail = null;
    284                         Node<K,V> next;
    285                         do {
    286                             next = e.next;
    287                             if ((e.hash & oldCap) == 0) {
    288                                 if (loTail == null)
    289                                     loHead = e;
    290                                 else
    291                                     loTail.next = e;
    292                                 loTail = e;
    293                             }
    294                             else {
    295                                 if (hiTail == null)
    296                                     hiHead = e;
    297                                 else
    298                                     hiTail.next = e;
    299                                 hiTail = e;
    300                             }
    301                         } while ((e = next) != null);
    302                         if (loTail != null) {
    303                             loTail.next = null;
    304                             newTab[j] = loHead;
    305                         }
    306                         if (hiTail != null) {
    307                             hiTail.next = null;
    308                             newTab[j + oldCap] = hiHead;
    309                         }
    310                     }
    311                 }
    312             }
    313         }
    314         return newTab;
    315     }
    316 //Get方法,加入很多的判断,以保证数据的准确性
    317     public V get(Object key) {
    318         Node<K,V> e;
    319         return (e = getNode(hash(key), key)) == null ? null : e.value;
    320     }
    321     
    322    final Node<K,V> getNode(int hash, Object key) {
    323         Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
    324         if ((tab = table) != null && (n = tab.length) > 0 &&
    325             (first = tab[(n - 1) & hash]) != null) {
    326             if (first.hash == hash && // always check first node
    327                 ((k = first.key) == key || (key != null && key.equals(k))))
    328                 return first;
    329             if ((e = first.next) != null) {
    330                 if (first instanceof TreeNode)
    331                     return ((TreeNode<K,V>)first).getTreeNode(hash, key);//如果是红黑树,则用红黑树的get方法
    332                 do {
    333                     if (e.hash == hash &&
    334                         ((k = e.key) == key || (key != null && key.equals(k))))
    335                         return e;
    336                 } while ((e = e.next) != null);
    337             }
    338         }
    339         return null;
    340     }
    341 //1.8取消了contans方法,用containsKey和ContainsValue
    342     public boolean containsKey(Object key) {
    343         return getNode(hash(key), key) != null;
    344     }
    345 
    346     public boolean containsValue(Object value) {
    347         Node<K,V>[] tab; V v;
    348         if ((tab = table) != null && size > 0) {
    349             for (int i = 0; i < tab.length; ++i) {
    350                 for (Node<K,V> e = tab[i]; e != null; e = e.next) {
    351                     if ((v = e.value) == value ||
    352                         (value != null && value.equals(v)))
    353                         return true;
    354                 }
    355             }
    356         }
    357         return false;
    358     }
    359 //entrySet方法
    360     public Set<Map.Entry<K,V>> entrySet() {
    361         Set<Map.Entry<K,V>> es;
    362         return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
    363     }
    364 
    365    final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
    366         public final int size()                 { return size; }
    367         public final void clear()               { HashMap.this.clear(); }
    368         public final Iterator<Map.Entry<K,V>> iterator() {
    369             return new EntryIterator();
    370         }
    371         public final boolean contains(Object o) {
    372             if (!(o instanceof Map.Entry))
    373                 return false;
    374             Map.Entry<?,?> e = (Map.Entry<?,?>) o;
    375             Object key = e.getKey();
    376             Node<K,V> candidate = getNode(hash(key), key);
    377             return candidate != null && candidate.equals(e);
    378         }
    379         public final boolean remove(Object o) {
    380             if (o instanceof Map.Entry) {
    381                 Map.Entry<?,?> e = (Map.Entry<?,?>) o;
    382                 Object key = e.getKey();
    383                 Object value = e.getValue();
    384                 return removeNode(hash(key), key, value, true, true) != null;
    385             }
    386             return false;
    387         }
    388         public final Spliterator<Map.Entry<K,V>> spliterator() {
    389             return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
    390         }
    391         public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
    392             Node<K,V>[] tab;
    393             if (action == null)
    394                 throw new NullPointerException();
    395             if (size > 0 && (tab = table) != null) {
    396                 int mc = modCount;
    397                 for (int i = 0; i < tab.length; ++i) {
    398                     for (Node<K,V> e = tab[i]; e != null; e = e.next)
    399                         action.accept(e);
    400                 }
    401                 if (modCount != mc)
    402                     throw new ConcurrentModificationException();
    403             }
    404         }
    405     }
    406 //keySet
    407     public Set<K> keySet() {
    408         Set<K> ks;
    409         return (ks = keySet) == null ? (keySet = new KeySet()) : ks;
    410     }
    411 
    412     final class KeySet extends AbstractSet<K> {
    413         public final int size()                 { return size; }
    414         public final void clear()               { HashMap.this.clear(); }
    415         public final Iterator<K> iterator()     { return new KeyIterator(); }
    416         public final boolean contains(Object o) { return containsKey(o); }
    417         public final boolean remove(Object key) {
    418             return removeNode(hash(key), key, null, false, true) != null;
    419         }
    420         public final Spliterator<K> spliterator() {
    421             return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
    422         }
    423         public final void forEach(Consumer<? super K> action) {
    424             Node<K,V>[] tab;
    425             if (action == null)
    426                 throw new NullPointerException();
    427             if (size > 0 && (tab = table) != null) {
    428                 int mc = modCount;
    429                 for (int i = 0; i < tab.length; ++i) {
    430                     for (Node<K,V> e = tab[i]; e != null; e = e.next)
    431                         action.accept(e.key);
    432                 }
    433                 if (modCount != mc)
    434                     throw new ConcurrentModificationException();
    435             }
    436         }
    437     }
    438 //remove方法
    439     public boolean remove(Object key, Object value) {
    440         return removeNode(hash(key), key, value, true, true) != null;
    441     }
    442 
    443     final Node<K,V> removeNode(int hash, Object key, Object value,
    444                                boolean matchValue, boolean movable) {
    445         Node<K,V>[] tab; Node<K,V> p; int n, index;
    446         if ((tab = table) != null && (n = tab.length) > 0 &&
    447             (p = tab[index = (n - 1) & hash]) != null) {
    448             Node<K,V> node = null, e; K k; V v;
    449             if (p.hash == hash &&
    450                 ((k = p.key) == key || (key != null && key.equals(k))))
    451                 node = p;
    452             else if ((e = p.next) != null) {
    453                 if (p instanceof TreeNode)
    454                     node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
    455                 else {
    456                     do {
    457                         if (e.hash == hash &&
    458                             ((k = e.key) == key ||
    459                              (key != null && key.equals(k)))) {
    460                             node = e;
    461                             break;
    462                         }
    463                         p = e;
    464                     } while ((e = e.next) != null);
    465                 }
    466             }
    467             if (node != null && (!matchValue || (v = node.value) == value ||
    468                                  (value != null && value.equals(v)))) {
    469                 if (node instanceof TreeNode)
    470                     ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
    471                 else if (node == p)
    472                     tab[index] = node.next;
    473                 else
    474                     p.next = node.next;
    475                 ++modCount;
    476                 --size;
    477                 afterNodeRemoval(node);
    478                 return node;
    479             }
    480         }
    481         return null;
    482     }
    483 //size方法和isEmpty方法
    484     transient int size;//和put以及remove方法有关系,增加就++,删除就--
    485     
    486     public int size() {
    487         return size;
    488     }
    489     
    490     public boolean isEmpty() {
    491         return size == 0;
    492     }
    View Code

    对比一下可以发现,在JDK1.8的时候,hashmap有了很大的改变,不止加了很多小的优化,而且还添加红黑树用来解决哈希碰撞导致的的查询问题。

    补充:

    为什么要转换为红黑树?
    红黑树具有很高效的查找功能,当数值不多时用链表的形式就可以应对问题,但是当链表很长的时候(发生了哈希碰撞多),hashmap在进行put和get等方法时都需要遍历链表,红黑树可以保证hashmap在发生哈希碰撞时能保证数据元素的高效定位。

    为什么转为红黑树的阈(yu)值为8?
    因为由链表转换成红黑树时,需要额外的空间和时间,作者根据“泊松分布”算出,出现链表长度为8的情况已经非常小了,大概是:0.00000006,所以在8的时候再转换为红黑树。

  • 相关阅读:
    1011. A+B和C (15)
    1010. 一元多项式求导 (25)
    1009. 说反话 (20)
    1007. 素数对猜想 (20)
    1008. 数组元素循环右移问题 (20)
    1006. 换个格式输出整数 (15)
    1005. 继续(3n+1)猜想 (25)
    算法学习(八)
    算法学习(七)
    算法学习(六)
  • 原文地址:https://www.cnblogs.com/Bernard94/p/12323498.html
Copyright © 2011-2022 走看看