1.7的HashMap是用数组+链表实现的
参数
//默认容量16static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;//最大容量static final int MAXIMUM_CAPACITY = 1 << 30;//默认加载因子static final float DEFAULT_LOAD_FACTOR = 0.75f;//空数组实例static final Entry<?,?>[] EMPTY_TABLE = {};//hashMap存储元素的数组transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;//hashMap存的元素数量(包括链表的元素)transient int size;//阈值,用在扩容时判断,capacity * load factorint threshold;//加载因子final float loadFactor;
Put方法
public V put(K key, V value) {if (table == EMPTY_TABLE) {//初始化hashMapinflateTable(threshold);}if (key == null)return putForNullKey(value);//计算hash值int hash = hash(key);//计算key在数组的索引indexint i = indexFor(hash, table.length);for (Entry<K,V> e = table[i]; e != null; e = e.next) {Object k;//如果put的新值,hash值已经存在,而且key也相同,则替换值,返回旧值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;}//计算索引位置static int indexFor(int h, int length) {//用hash值和(数组长度-1)进行与&运行//假设数组长度是16,那length-1就是15,转换成2进制就是1111// 假设hash值是 1101 1001// & 0000 1111// 0000 1001//最后得出得index是9,这样可以保证不会数组越界和均匀分布return h & (length-1);}//初始化hashMap的数组private void inflateTable(int toSize) {// 要保证长度是2的幂次方,例如8,16,32...int capacity = roundUpToPowerOf2(toSize);//计算当前的阈值threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);table = new Entry[capacity];initHashSeedAsNeeded(capacity);}//key为null时特殊处理//key=null,会把null放在hashMap数组的第一个位置,重复会覆盖private V putForNullKey(V value) {for (Entry<K,V> e = table[0]; e != null; e = e.next) {if (e.key == null) {V oldValue = e.value;e.value = value;e.recordAccess(this);return oldValue;}}modCount++;addEntry(0, null, value, 0);return null;}void addEntry(int hash, K key, V value, int bucketIndex) {//判断扩容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);}void createEntry(int hash, K key, V value, int bucketIndex) {//获取当前索引位置的值Entry<K,V> e = table[bucketIndex];//创建一个entry,并把entry的next节点指向e(头插法)//然后把当前数组索引位置的值赋值为新创建的entrytable[bucketIndex] = new Entry<>(hash, key, value, e);size++;}
