数据结构(集合)学习之Map(一)

集合

框架关系图:

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时不直接生成数组了,采用懒加载的方式,在用的时候再初始化。

扫描二维码关注公众号,回复: 9353900 查看本文章

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,底层是Entry数组+链表+红黑树:

  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的时候再转换为红黑树。

猜你喜欢

转载自www.cnblogs.com/Bernard94/p/12323498.html