1、HashMap构造方法
HashMap<String, String> map = new HashMap<>(); public HashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); }
空的构造方法默认调用有参结构
DEFAULT_INITIAL_CAPACITY 默认大小 16DEFAULT_LOAD_FACTOR 默认加载因子 0.75
public HashMap(int initialCapacity, float loadFactor) { //做参数校验 加载因子 容量大小 (大于0 小于等于MAXIMUM_CAPACITY) this.loadFactor = loadFactor; threshold = initialCapacity; init(); }
2、put办法
map.put("k1", "v1");//put办法public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
2.1 inflateTable
办法
/** * Inflates the table. */ private void inflateTable(int toSize) { // Find a power of 2 >= toSize //该办法用于寻找一个大于或等于该数的一个2的幂次方数, //为前期扩容或计算元素寄存地位 int capacity = roundUpToPowerOf2(toSize); threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); table = new Entry[capacity]; initHashSeedAsNeeded(capacity); }
2.1.1 roundUpToPowerOf2
办法
private static int roundUpToPowerOf2(int number) { // assert number >= 0 : "number must be non-negative"; int rounded = number >= MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY : (rounded = Integer.highestOneBit(number)) != 0 ? (Integer.bitCount(number) > 1) ? rounded << 1 : rounded : 1; return rounded; } /** * 该办法用于返回一个小于等于i的一个2的幂次方数 * 采纳的的办法为最高为 1 */public static int highestOneBit(int i) { // HD, Figure 3-1 i |= (i >> 1); i |= (i >> 2); i |= (i >> 4); i |= (i >> 8); i |= (i >> 16); //这里i得出为 00....0 1111 //i >>> 1 00....0 0111 //减去失去 00....0 1000 return i - (i >>> 1); }
该办法就是讲hash值与对应的Entry数组的长度进行与运算 static int indexFor(int h, int length) { // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2"; return h & (length-1); }
final int hash(Object k) { int h = hashSeed; if (0 != h && k instanceof String) { return sun.misc.Hashing.stringHash32((String) k); } h ^= k.hashCode(); // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). //为了让数组元素寄存的更加散列让高位也参加运算 h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }
2.2 addEntry
办法
void addEntry(int hash, K key, V value, int bucketIndex) { //当寄存元素个数超过容量*加载因子 且以后下标为 bucketIndex的table曾经寄存过元素则扩容 if ((size >= threshold) && (null != table[bucketIndex])) { resize(2 * table.length); hash = (null != key) ? hash(key) : 0; bucketIndex = indexFor(hash, table.length); } createEntry(hash, key, value, bucketIndex); }
2.2.1 createEntry()
办法
void createEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; //这里实现的逻辑就是将 新的Entry对象 的next指向table[bucketIndex] 以后寄存的元素, 而后将table[bucketIndex] 指向新的Entry对象 table[bucketIndex] = new Entry<>(hash, key, value, e); size++; }
2.2.2 resize()
办法
// newCapacity为之前数组元素长度的两倍 void resize(int newCapacity) { //转移元素到新数组 transfer(newTable, initHashSeedAsNeeded(newCapacity)); }
/** * Initialize the hashing mask value. We defer initialization until we * really need it. */ //该办法就是为了从新生成hahs种子 final boolean initHashSeedAsNeeded(int capacity) { //这里hashSeed之前默认为0 所以为false boolean currentAltHashing = hashSeed != 0; boolean useAltHashing = sun.misc.VM.isBooted() && (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); //所以这里只有当useAltHashing返回true //才会从新计算hashSeed boolean switching = currentAltHashing ^ useAltHashing; if (switching) { hashSeed = useAltHashing ? sun.misc.Hashing.randomHashSeed(this) : 0; } return switching; }
transfer
办法
void transfer(Entry[] newTable, boolean rehash) { int newCapacity = newTable.length; //遍历以后Entry数组以及链表 即遍历所有元素 //这里在并发环境下,会呈现循环列表的状况 //所以在get或put的时候就可能会导致死循环 for (Entry<K,V> e : table) { while(null != e) { Entry<K,V> next = e.next; if (rehash) { e.hash = null == e.key ? 0 : hash(e.key); } int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } } }