一 特性

  • 键之间的比较不是食用equals 而是使用==也就是比较内存地址
  • 可以使用这个存储代理对象
  • 支持null值的key和value
  • 是非线程安全的,可以借助Collections.synchronizedMap 来获得线程安全的实例
  • 采用开放寻址方式解决hash冲突

    二 属性

    1. /**
    2. * The initial capacity used by the no-args constructor.
    3. * MUST be a power of two. The value 32 corresponds to the
    4. * (specified) expected maximum size of 21, given a load factor
    5. * of 2/3. 无参数构造函数使用这个默认值初始化
    6. */
    7. private static final int DEFAULT_CAPACITY = 32;
    8. /**
    9. * The minimum capacity, used if a lower value is implicitly specified
    10. * by either of the constructors with arguments. The value 4 corresponds
    11. * to an expected maximum size of 2, given a load factor of 2/3.
    12. * MUST be a power of two. 最小的容量
    13. */
    14. private static final int MINIMUM_CAPACITY = 4;
    15. /**
    16. * The maximum capacity, used if a higher value is implicitly specified
    17. * by either of the constructors with arguments.
    18. * MUST be a power of two <= 1<<29.
    19. *
    20. * In fact, the map can hold no more than MAXIMUM_CAPACITY-1 items
    21. * because it has to have at least one slot with the key == null
    22. * in order to avoid infinite loops in get(), put(), remove()
    23. */
    24. private static final int MAXIMUM_CAPACITY = 1 << 29;
    25. /**
    26. * The table, resized as necessary. Length MUST always be a power of two.
    27. */
    28. transient Object[] table; // non-private to simplify nested class access
    29. /**
    30. * The number of key-value mappings contained in this identity hash map.
    31. *
    32. * @serial
    33. */
    34. int size;
    35. /**
    36. * The number of modifications, to support fast-fail iterators
    37. */
    38. transient int modCount;
    39. /**
    40. * Value representing null keys inside tables.
    41. */
    42. static final Object NULL_KEY = new Object();

    三 重要方法

  • hash

    • 计算hash值的方法 ((h << 1) - (h << 8)) & (length - 1)
  • nextKeyIndex
    • 计算给定位置的hash冲突的解决为止,采用开放寻址方式解决hash冲突
  • resize

    • 扩容方法 扩容的大小是原来大小的两倍,会创建一个新的数组并将每个元素重进进行hash

      四 添加

      1. public V put(K key, V value) {
      2. final Object k = maskNull(key);
      3. retryAfterResize: for (;;) {
      4. final Object[] tab = table;
      5. final int len = tab.length;
      6. int i = hash(k, len);
      7. //这里的循环的为开放寻址法的地址 i = nextKeyIndex(i, len) 来控制的
      8. for (Object item; (item = tab[i]) != null;
      9. i = nextKeyIndex(i, len)) {
      10. if (item == k) {
      11. @SuppressWarnings("unchecked")
      12. V oldValue = (V) tab[i + 1];
      13. tab[i + 1] = value;
      14. return oldValue;
      15. }
      16. }
      17. final int s = size + 1;
      18. // Use optimized form of 3 * s.
      19. // Next capacity is len, 2 * current capacity.
      20. //判断当前已经存在的元素的 2.5倍是否大于数组的长度 扩容后重新retryAfterResize
      21. if (s + (s << 1) > len && resize(len))
      22. continue retryAfterResize;
      23. modCount++;
      24. tab[i] = k;
      25. tab[i + 1] = value;
      26. size = s;
      27. return null;
      28. }
      29. }

      五 删除

      1. public V remove(Object key) {
      2. Object k = maskNull(key);
      3. Object[] tab = table;
      4. int len = tab.length;
      5. int i = hash(k, len);
      6. //具体的删除过程
      7. while (true) {
      8. Object item = tab[i];
      9. if (item == k) {
      10. modCount++;
      11. size--;
      12. @SuppressWarnings("unchecked")
      13. V oldValue = (V) tab[i + 1];
      14. tab[i + 1] = null;
      15. tab[i] = null;
      16. closeDeletion(i);
      17. return oldValue;
      18. }
      19. if (item == null)
      20. return null;
      21. i = nextKeyIndex(i, len);
      22. }
      23. }

      六 获取

      1. public V get(Object key) {
      2. Object k = maskNull(key);
      3. Object[] tab = table;
      4. int len = tab.length;
      5. int i = hash(k, len);
      6. while (true) {
      7. Object item = tab[i];
      8. if (item == k)
      9. return (V) tab[i + 1];
      10. if (item == null)
      11. return null;
      12. //如果都不等于则代表发生了hash冲突,使用开放寻址方式找下一个位置
      13. i = nextKeyIndex(i, len);
      14. }
      15. }

      七 resize

      1. private boolean resize(int newCapacity) {
      2. // assert (newCapacity & -newCapacity) == newCapacity; // power of 2 新大小是原来的两倍
      3. int newLength = newCapacity * 2;
      4. Object[] oldTable = table;
      5. int oldLength = oldTable.length;
      6. if (oldLength == 2 * MAXIMUM_CAPACITY) { // can't expand any further
      7. if (size == MAXIMUM_CAPACITY - 1)
      8. throw new IllegalStateException("Capacity exhausted.");
      9. return false;
      10. }
      11. if (oldLength >= newLength)
      12. return false;
      13. Object[] newTable = new Object[newLength];
      14. //重新进行更新hash槽位的过程
      15. for (int j = 0; j < oldLength; j += 2) {
      16. Object key = oldTable[j];
      17. if (key != null) {
      18. Object value = oldTable[j+1];
      19. oldTable[j] = null;
      20. oldTable[j+1] = null;
      21. int i = hash(key, newLength);
      22. while (newTable[i] != null)
      23. i = nextKeyIndex(i, newLength);
      24. newTable[i] = key;
      25. newTable[i + 1] = value;
      26. }
      27. }
      28. table = newTable;
      29. return true;
      30. }