源码分析 - JDK 1.7

    1. //1. HashMap 的 K,V的值,在创建对象的时候确定,比如:K:Integer V: String
    2. public class HashMap<K,V>
    3. extends AbstractMap<K,V>
    4. implements Map<K,V>, Cloneable, Serializable
    5. {
    6. //重要属性:定义了一个16,赋给初始化数组长度
    7. static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
    8. //定义了一个很大很大的数
    9. static final int MAXIMUM_CAPACITY = 1 << 30;
    10. //定义了加载因子,为 0.75
    11. static final float DEFAULT_LOAD_FACTOR = 0.75f;
    12. //定义空的主数组
    13. static final Entry<?,?>[] EMPTY_TABLE = {};
    14. //添加的元素的数量
    15. transient int size;
    16. //定义个变量,没赋值,为0 。 --- 这个变量用来表示数组扩容的边界值,
    17. int threshold;
    18. //加载因子,这个变量用来接收 加载因子的值
    19. final float loadFactor;
    20. }

    构造器

    1. //空构造器
    2. public HashMap() {
    3. //this.(16,0.75)
    4. this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
    5. }
    6. //有参的构造器, 16, 0.75 ---------》 不建议使用者调用这个构造器
    7. public HashMap(int initialCapacity, float loadFactor) {
    8. if (loadFactor <= 0 || Float.isNaN(loadFactor))
    9. throw new IllegalArgumentException("Illegal load factor: " +
    10. loadFactor);
    11. //确定了加载因子,0.75
    12. this.loadFactor = loadFactor;
    13. //扩展数组的边界值
    14. threshold = initialCapacity;
    15. init();
    16. }

    PUT方法

    1. public V put(K key, V value) {
    2. if (table == EMPTY_TABLE) {
    3. inflateTable(threshold);
    4. }
    5. if (key == null) // 对空值进行判断,允许key的值为空
    6. return putForNullKey(value);
    7. int hash = hash(key); // 获取hash码
    8. int i = indexFor(hash, table.length);//得到元素在数组中的位置
    9. // 通过放入的数组上,没有元素的话,那么直接添加元素,不走这个for循环。
    10. //如果e!= null 满足,就证明这个位置上有元素,
    11. for (Entry<K,V> e = table[i]; e != null; e = e.next) {
    12. Object k;
    13. //发生哈希碰撞的时候,会先比较哈希值,
    14. // 比较key是否是一个对象,如果是,equals就不比较了
    15. // 比较key是否是一个对象,如果不是,则比较equals
    16. // 如果hash值一样,equals方法比较的结果也一样,那么才会走这个方法
    17. if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
    18. V oldValue = e.value;
    19. e.value = value;// 新value 替换 老 value, 只替换value,不替换value
    20. e.recordAccess(this);
    21. return oldValue;// 将old 的value返回,即原始的value值
    22. }
    23. }
    24. addEntry(hash, key, value, i);
    25. return null;
    26. }
    27. // 获取Key 的 hashcode 的方法
    28. final int hash(Object k) {
    29. int h = hashSeed;
    30. if (0 != h && k instanceof String) {
    31. return sun.misc.Hashing.stringHash32((String) k);
    32. }
    33. //进行了二次散列,没有直接用hashcode的值性,减少冲突
    34. h ^= k.hashCode();
    35. //扰动函数,核心思想:增加hashcode的不确定
    36. h ^= (h >>> 20) ^ (h >>> 12);
    37. return h ^ (h >>> 7) ^ (h >>> 4);
    38. }
    39. static int indexFor(int h, int length) {
    40. // 计算位置对应的公示,等效于 h % length取余数,因为这样效率高
    41. return h & (length-1);
    42. }
    43. //添加元素的方法
    44. void addEntry(int hash, K key, V value, int bucketIndex) {
    45. //如果这个size 》= threshold ,这个if不走了
    46. if ((size >= threshold) && (null != table[bucketIndex])) {
    47. resize(2 * table.length);
    48. hash = (null != key) ? hash(key) : 0;
    49. bucketIndex = indexFor(hash, table.length);
    50. }
    51. //创建一个Entry对象
    52. createEntry(hash, key, value, bucketIndex);
    53. }
    54. //创建一个Entry对象
    55. void createEntry(int hash, K key, V value, int bucketIndex) {
    56. //将下标位置上的元素给e
    57. Entry<K,V> e = table[bucketIndex];
    58. //封装对象,将这个对象给table[bucketIndex] -----------》 链表的《头插法》
    59. table[bucketIndex] = new Entry<>(hash, key, value, e);
    60. //元素数量+1
    61. size++;
    62. }

    扩容resize

    1. //添加元素的方法
    2. void addEntry(int hash, K key, V value, int bucketIndex) {
    3. //如果这个size 》= threshold ,这个if不走了
    4. if ((size >= threshold) && (null != table[bucketIndex])) { // 如果size 大于 12(16*0.75) 并且 该位置有元素了,才会去扩容
    5. resize(2 * table.length); // 扩容大为2倍
    6. hash = (null != key) ? hash(key) : 0;
    7. bucketIndex = indexFor(hash, table.length);
    8. }
    9. //创建一个Entry对象
    10. createEntry(hash, key, value, bucketIndex);
    11. }
    12. void resize(int newCapacity) {
    13. Entry[] oldTable = table;
    14. int oldCapacity = oldTable.length;
    15. if (oldCapacity == MAXIMUM_CAPACITY) {
    16. threshold = Integer.MAX_VALUE;
    17. return;
    18. }
    19. Entry[] newTable = new Entry[newCapacity];
    20. transfer(newTable, initHashSeedAsNeeded(newCapacity)); // transfer 将新数组给老数组
    21. table = newTable;
    22. threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
    23. }