1.7的HashMap是用数组+链表实现的
04-13 HashMap-1.7JDK - 图1

参数

  1. //默认容量16
  2. static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
  3. //最大容量
  4. static final int MAXIMUM_CAPACITY = 1 << 30;
  5. //默认加载因子
  6. static final float DEFAULT_LOAD_FACTOR = 0.75f;
  7. //空数组实例
  8. static final Entry<?,?>[] EMPTY_TABLE = {};
  9. //hashMap存储元素的数组
  10. transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
  11. //hashMap存的元素数量(包括链表的元素)
  12. transient int size;
  13. //阈值,用在扩容时判断,capacity * load factor
  14. int threshold;
  15. //加载因子
  16. final float loadFactor;

Put方法

  1. public V put(K key, V value) {
  2. if (table == EMPTY_TABLE) {
  3. //初始化hashMap
  4. inflateTable(threshold);
  5. }
  6. if (key == null)
  7. return putForNullKey(value);
  8. //计算hash值
  9. int hash = hash(key);
  10. //计算key在数组的索引index
  11. int i = indexFor(hash, table.length);
  12. for (Entry<K,V> e = table[i]; e != null; e = e.next) {
  13. Object k;
  14. //如果put的新值,hash值已经存在,而且key也相同,则替换值,返回旧值
  15. if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
  16. V oldValue = e.value;
  17. e.value = value;
  18. e.recordAccess(this);
  19. return oldValue;
  20. }
  21. }
  22. modCount++;
  23. addEntry(hash, key, value, i);
  24. return null;
  25. }
  26. //计算索引位置
  27. static int indexFor(int h, int length) {
  28. //用hash值和(数组长度-1)进行与&运行
  29. //假设数组长度是16,那length-1就是15,转换成2进制就是1111
  30. // 假设hash值是 1101 1001
  31. // & 0000 1111
  32. // 0000 1001
  33. //最后得出得index是9,这样可以保证不会数组越界和均匀分布
  34. return h & (length-1);
  35. }
  36. //初始化hashMap的数组
  37. private void inflateTable(int toSize) {
  38. // 要保证长度是2的幂次方,例如8,16,32...
  39. int capacity = roundUpToPowerOf2(toSize);
  40. //计算当前的阈值
  41. threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
  42. table = new Entry[capacity];
  43. initHashSeedAsNeeded(capacity);
  44. }
  45. //key为null时特殊处理
  46. //key=null,会把null放在hashMap数组的第一个位置,重复会覆盖
  47. private V putForNullKey(V value) {
  48. for (Entry<K,V> e = table[0]; e != null; e = e.next) {
  49. if (e.key == null) {
  50. V oldValue = e.value;
  51. e.value = value;
  52. e.recordAccess(this);
  53. return oldValue;
  54. }
  55. }
  56. modCount++;
  57. addEntry(0, null, value, 0);
  58. return null;
  59. }
  60. void addEntry(int hash, K key, V value, int bucketIndex) {
  61. //判断扩容
  62. if ((size >= threshold) && (null != table[bucketIndex])) {
  63. //每次扩容数组容量的一倍
  64. resize(2 * table.length);
  65. hash = (null != key) ? hash(key) : 0;
  66. bucketIndex = indexFor(hash, table.length);
  67. }
  68. createEntry(hash, key, value, bucketIndex);
  69. }
  70. void createEntry(int hash, K key, V value, int bucketIndex) {
  71. //获取当前索引位置的值
  72. Entry<K,V> e = table[bucketIndex];
  73. //创建一个entry,并把entry的next节点指向e(头插法)
  74. //然后把当前数组索引位置的值赋值为新创建的entry
  75. table[bucketIndex] = new Entry<>(hash, key, value, e);
  76. size++;
  77. }