集合
框架关系图:
补充: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 }
补充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 }
对比可以看出,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 }
对比一下可以发现,在JDK1.8的时候,hashmap有了很大的改变,不止加了很多小的优化,而且还添加红黑树用来解决哈希碰撞导致的的查询问题。
补充:
为什么要转换为红黑树?
红黑树具有很高效的查找功能,当数值不多时用链表的形式就可以应对问题,但是当链表很长的时候(发生了哈希碰撞多),hashmap在进行put和get等方法时都需要遍历链表,红黑树可以保证hashmap在发生哈希碰撞时能保证数据元素的高效定位。
为什么转为红黑树的阈(yu)值为8?
因为由链表转换成红黑树时,需要额外的空间和时间,作者根据“泊松分布”算出,出现链表长度为8的情况已经非常小了,大概是:0.00000006,所以在8的时候再转换为红黑树。