1、构造方法
1 public HashMap() { 2 this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); 3 } 4 5 public HashMap(int initialCapacity) { 6 this(initialCapacity, DEFAULT_LOAD_FACTOR); 7 } 8 9 public HashMap(int initialCapacity, float loadFactor) { 10 if (initialCapacity < 0) 11 throw new IllegalArgumentException("Illegal initial capacity: " + 12 initialCapacity); 13 if (initialCapacity > MAXIMUM_CAPACITY) 14 initialCapacity = MAXIMUM_CAPACITY; 15 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 16 throw new IllegalArgumentException("Illegal load factor: " + 17 loadFactor); 18 19 this.loadFactor = loadFactor; 20 threshold = initialCapacity; 21 init(); 22 } 23 24 public HashMap(Map<? extends K, ? extends V> m) { 25 this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, 26 DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); 27 inflateTable(threshold); 28 29 putAllForCreate(m); 30 }
4种构造方法
1、无参的构造方法,也就是我们最常用的构造方法,他给我们的默认的初始化 容量是16 也就是entry[]数组是16 ,entry 有什么参数?
一共4个参数,key, value ,hash ,还有一个就是Entry<K,V> next 对象中的对象,负载因子默认是0.75
2、给一个数组大小的参数的是第二个构造函数
3、给两个的是上面所说的两个参数的构造函数,内容就是检验入参,最后的是初始化链表,这里是个空的方法,为的是子类要可以重写方法
put方法
//入参是key和value public V put(K key, V value) { 判断表中是不是没有数据 if (table == EMPTY_TABLE) { 如果没有数据就调用这个方法(入参是容量* 负载因子) inflateTable(threshold); } 如果key 为空返回下面的方法。作用: 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; } /** * Inflates the table. */ private void inflateTable(int toSize) { // 找到2的n次幂 >= 这个入参 例如:2^4>15 这个capacity =16 int capacity = roundUpToPowerOf2(toSize); 获取合理的负载因子, threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); 新建一个这么大的容量的数组并复给table table = new Entry[capacity]; //初始化哈希掩码值 initHashSeedAsNeeded(capacity); } //入参是插入进来的value private V putForNullKey(V value) { 循环这个数组的第一个数组 的链表, for (Entry<K,V> e = table[0]; e != null; e = e.next) { 如果链表中的第一个值的 key值为空则把value值付给第一个原数的value if (e.key == null) { V oldValue = e.value; e.value = value; //空方法 e.recordAccess(this); //返回老的value值,就是对数组做操作仅仅是变更了一下value值, return oldValue; } } 数组变更次数加一 modCount++; 设置hash值为零,key值为null value为入参的值 addEntry(0, null, value, 0); return null; void addEntry(int hash, K key, V value, int bucketIndex) { 判断数组中的数据是否大于负载因子并且数组的第一个元素为空 if ((size >= threshold) && (null != table[bucketIndex])) { 扩2被的数值长度 resize(2 * table.length); hash = (null != key) ? hash(key) : 0; bucketIndex = indexFor(hash, table.length); } 入参是原来长度的2被 void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; 如果超过最大了就直接返回不扩容了 if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } 新建一个这么大的数组, Entry[] newTable = new Entry[newCapacity]; 把老的数组中的数转换到新数组中 transfer(newTable, initHashSeedAsNeeded(newCapacity)); table = newTable; threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1); } void transfer(Entry[] newTable, boolean rehash) { int newCapacity = newTable.length; 循环原有的数组 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); }重置这个hash值,与运算,也就是获取一个位置,放到先新的数组中的位置 int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } } }