HashMap 实现总结
- Entry类中需包含键值的hash值,防止resize时的重复计算;
- Map容量为2的整幂,可使用位操作取代取余操作提高效率;
- resize时需要将原table的桶内数据置null,利于垃圾回收;
- hash函数考虑数据高位的影响,可减少冲突。
1 public class MyHashMap<K, V> implements IMap<K, V> { 2 static final float DEFAULT_LOAD_FACTOR = 0.75f; 3 static final int DEFAULT_CAPACITY = 16; 4 5 Entry<K, V>[] table; 6 int size; 7 /** 8 * 装载因子 9 */ 10 float loadFactor; 11 /** 12 * 实际的容量 13 */ 14 int threshold; 15 16 public MyHashMap() { 17 this.loadFactor = DEFAULT_LOAD_FACTOR; 18 this.threshold = (int) (DEFAULT_CAPACITY * loadFactor); 19 table = new Entry[DEFAULT_CAPACITY]; 20 } 21 22 public MyHashMap(int initialCapacity, float loadFactor) { 23 /** 24 * 缺少参数检查 25 */ 26 int capacity = 1; 27 while (capacity < initialCapacity) { 28 capacity <<= 1; 29 } 30 this.loadFactor = loadFactor; 31 this.threshold = (int) (capacity * loadFactor); 32 table = new Entry[capacity]; 33 } 34 35 public MyHashMap(int initialCapacity) { 36 this(initialCapacity, DEFAULT_LOAD_FACTOR); 37 } 38 39 /** 40 * 算术右移,计入高位影响 41 */ 42 static int hash(int h) { 43 return h ^ (h >>> 20) ^ (h >>> 12) ^ (h >>> 7) ^ (h >>> 4); 44 } 45 46 @Override 47 public V put(K k, V v) { 48 if (k == null) { 49 putForNull(v); 50 } 51 int hash = hash(k.hashCode()); 52 int i = indexFor(hash, table.length); 53 for (Entry<K, V> e = table[i]; e != null; e = e.next) { 54 if (e.key.hashCode() == k.hashCode() 55 && (e.key == k || (k != null && k.equals(e.key)))) { 56 V oldValue = e.value; 57 e.value = v; 58 return oldValue; 59 } 60 } 61 addEntry(k, v, i); 62 return null; 63 } 64 65 private void addEntry(K k, V v, int index) { 66 Entry<K, V> e = new Entry<K, V>(k, v, table[index]); 67 table[index] = e; 68 if (size++ > threshold) { 69 resize(table.length * 2); 70 } 71 } 72 73 void resize(int newCapacity) { 74 Entry[] newTable = new Entry[newCapacity]; 75 transfer(newTable); 76 table = newTable; 77 threshold = (int) (newCapacity * loadFactor); 78 System.out.println("resize()" + " current capacity: " + table.length); 79 } 80 81 void transfer(Entry[] newTable) { 82 for (int i = 0; i < table.length; i++) { 83 Entry<K, V> e = table[i]; 84 if (e != null) { 85 /** 86 * 需要將原table置为空,方可释放内存 87 */ 88 table[i] = null; 89 do { 90 Entry<K, V> next = e.next; 91 /** 92 * 重复计算hash值,效率不高 93 */ 94 int index = indexFor(hash(e.key.hashCode()), 95 newTable.length); 96 e.next = newTable[index]; 97 newTable[index] = e; 98 e = next; 99 } while (e != null); 100 } 101 } 102 } 103 104 private V putForNull(V value) { 105 // 未实现 106 return value; 107 } 108 109 /** 110 * 用位操作取代取余操作,前提是数组长度为2的幂次 111 */ 112 private int indexFor(int hash, int length) { 113 return hash & (length - 1); 114 } 115 116 @Override 117 public V get(K k) { 118 int hash = hash(k.hashCode()); 119 int index = indexFor(hash, table.length); 120 Entry<K, V> e = table[index]; 121 while (e != null) { 122 if (e.key.hashCode() == k.hashCode() 123 && (e.key == k || (k != null && k.equals(e.key)))) { 124 return e.value; 125 } 126 e = e.next; 127 } 128 return null; 129 } 130 131 static class Entry<K, V> { 132 K key; 133 V value; 134 Entry<K, V> next; 135 int hash; 136 137 public Entry(K k, V v, Entry<K, V> n) { 138 key = k; 139 value = v; 140 next = n; 141 // hash = h; 142 } 143 144 public V setValue(V v) { 145 V oldValue = value; 146 value = v; 147 return oldValue; 148 } 149 150 public boolean equals(Object o) { 151 if (!(o instanceof MyHashMap.Entry)) { 152 return false; 153 } 154 Entry e = (Entry) o; 155 Object k1 = e.key; 156 Object k2 = key; 157 if (k1 == k2 || (k1 != null && k1.equals(k2))) { 158 Object v1 = e.value; 159 Object v2 = value; 160 if (v1 == v2 || (v1 != v2 && v2.equals(v2))) { 161 return true; 162 } 163 } 164 return false; 165 } 166 } 167 }