java.util.HashMap

本文目录:

一、HashMap的特点概述和说明

关注点 HashMap的相关结论
是否允许空的 key
是否允许重复的 key 否,实际上可能会进行覆盖更新
元素有序:读取数据和存放数据的顺序一致 否,读取和存放都无序
是否线程安全
通过 key 进行随机访问的效率 较快
添加元素的效率

较快

涉及扩容、列表转红黑树、遍历列表时相对慢

删除元素的效率 较快

这里主要提几点:

  1. Java8 中 HashMap 源码的大方向就是:数组 + 单向链表(数组的元素,Node 实例,包含四个属性:key, value, hash 值和用于单向链表的 next) + 红黑树(链表超过8个元素且总元素个数超过 64 时转换为红黑树),对于hash冲突的元素,使用链表进行存储,每次存储在链表末尾。
  2. capacity:当前数组容量,默认值是 16,自动扩容,但始终保持 2^n,即扩容后数组大小为当前的 2 倍。
  3. loadFactor:负载因子,默认为 0.75
  4. threshold:扩容的阈值,等于 capacity * loadFactor,当元素实际个数 size 大于等于 threshold 时,进行扩容。

  Java8的 HashMap,最大的改变,是使用了数组 + 链表 + 红黑树。当链表中的元素达到了 8 个且总元素个数超过64个时,会将链表转换为红黑树,在这些位置进行查找的时候可以由原来的耗时 O(N),降低到时间复杂度为 O(logN)。另附上简要示意图:

二、HashMap的内部实现:从内部属性和构造函数说起

1、常用的类属性

  常用的类属性如下,比如默认容量、负载因子等。

  1. /**
  2. * The default initial capacity - MUST be a power of two.
  3. * 默认的初始容量 16 = 2 ^ 4
  4. */
  5. static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
  6.  
  7. /**
  8. * The maximum capacity, used if a higher value is implicitly specified
  9. * by either of the constructors with arguments.
  10. * MUST be a power of two <= 1<<30.
  11. * 允许的最大容量
  12. */
  13. static final int MAXIMUM_CAPACITY = 1 << 30;
  14.  
  15. /**
  16. * The load factor used when none specified in constructor.
  17. * 默认的负载因子
  18. */
  19. static final float DEFAULT_LOAD_FACTOR = 0.75f;
  20.  
  21. /**
  22. * The bin count threshold for using a tree rather than list for a
  23. * bin. Bins are converted to trees when adding an element to a
  24. * bin with at least this many nodes. The value must be greater
  25. * than 2 and should be at least 8 to mesh with assumptions in
  26. * tree removal about conversion back to plain bins upon
  27. * shrinkage.
  28. * 达到需要转化为红黑树时的链表容量阈值
  29. */
  30. static final int TREEIFY_THRESHOLD = 8;
  31.  
  32. /**
  33. * The bin count threshold for untreeifying a (split) bin during a
  34. * resize operation. Should be less than TREEIFY_THRESHOLD, and at
  35. * most 6 to mesh with shrinkage detection under removal.
  36. * 红黑树转回链表的下限阈值
  37. */
  38. static final int UNTREEIFY_THRESHOLD = 6;
  39.  
  40. /**
  41. * The smallest table capacity for which bins may be treeified.
  42. * (Otherwise the table is resized if too many nodes in a bin.)
  43. * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
  44. * between resizing and treeification thresholds.
  45. * 达到需要转化为红黑树时的Map总容量最低阈值
  46. */
  47. static final int MIN_TREEIFY_CAPACITY = 64;

2、实例属性

  实例属性,包括内部实际存储元素的数组、Map 的实际大小、实际的负载因子、修改次数等

  1. /**
  2. * The table, initialized on first use, and resized as
  3. * necessary. When allocated, length is always a power of two.
  4. * (We also tolerate length zero in some operations to allow
  5. * bootstrapping mechanics that are currently not needed.)
  6. * 内部实际存储元素的数组
  7. */
  8. transient Node<K,V>[] table;
  9.  
  10. /**
  11. * Holds cached entrySet(). Note that AbstractMap fields are used
  12. * for keySet() and values().
  13. */
  14. transient Set<Map.Entry<K,V>> entrySet;
  15.  
  16. /**
  17. * The number of key-value mappings contained in this map.
  18. * map的大小,即实际的元素个数
  19. */
  20. transient int size;
  21.  
  22. /**
  23. * The number of times this HashMap has been structurally modified
  24. * Structural modifications are those that change the number of mappings in
  25. * the HashMap or otherwise modify its internal structure (e.g.,
  26. * rehash). This field is used to make iterators on Collection-views of
  27. * the HashMap fail-fast. (See ConcurrentModificationException).
  28. * 修改次数,用于 fail-fast 机制校验
  29. */
  30. transient int modCount;
  31.  
  32. /**
  33. * The next size value at which to resize (capacity * load factor).
  34. * 容量阈值,元素个数超过阈值是会进行扩容
  35. * @serial
  36. */
  37. // (The javadoc description is true upon serialization.
  38. // Additionally, if the table array has not been allocated, this
  39. // field holds the initial array capacity, or zero signifying
  40. // DEFAULT_INITIAL_CAPACITY.)
  41. int threshold;
  42.  
  43. /**
  44. * The load factor for the hash table.
  45. * 负载因子
  46. * @serial
  47. */
  48. final float loadFactor;

3、节点内部类

  这个是实际的元素存储节点。

  1. /**
  2. * Basic hash bin node, used for most entries. (See below for
  3. * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
  4. */
  5. static class Node<K,V> implements Map.Entry<K,V> {
  6. final int hash;
  7. final K key;
  8. V value;
  9. Node<K,V> next;
  10. ...
  11. }

4、构造函数

  几个构造函数中最主要的还是要设定初始的负载因子 loadFactor

  1. /**
  2. * Constructs an empty <tt>HashMap</tt> with the specified initial
  3. * capacity and load factor.
  4. * 指定 初始容量 和 负载因子
  5. * @param initialCapacity the initial capacity
  6. * @param loadFactor the load factor
  7. * @throws IllegalArgumentException if the initial capacity is negative
  8. * or the load factor is nonpositive
  9. */
  10. public HashMap(int initialCapacity, float loadFactor) {
  11. if (initialCapacity < 0)
  12. throw new IllegalArgumentException("Illegal initial capacity: " +
  13. initialCapacity);
  14. if (initialCapacity > MAXIMUM_CAPACITY)
  15. initialCapacity = MAXIMUM_CAPACITY;
  16. if (loadFactor <= 0 || Float.isNaN(loadFactor))
  17. throw new IllegalArgumentException("Illegal load factor: " +
  18. loadFactor);
  19. // 设定负载因子
  20. this.loadFactor = loadFactor;
  21. // 设定阈值为 大于等于指定初始容量且最小 的 2^n
  22. this.threshold = tableSizeFor(initialCapacity);
  23. }
  24.  
  25. /**
  26. * Constructs an empty <tt>HashMap</tt> with the specified initial
  27. * capacity and the default load factor (0.75).
  28. *
  29. * @param initialCapacity the initial capacity.
  30. * @throws IllegalArgumentException if the initial capacity is negative.
  31. */
  32. public HashMap(int initialCapacity) {
  33. // 使用默认的负载因子 0.75
  34. this(initialCapacity, DEFAULT_LOAD_FACTOR);
  35. }
  36.  
  37. /**
  38. * Constructs an empty <tt>HashMap</tt> with the default initial capacity
  39. * (16) and the default load factor (0.75).
  40. */
  41. public HashMap() {
  42. // 使用默认负载因子 0.75,而其他使用默认值,包括 阈值 threshold = 0
  43. this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
  44. }
  45.  
  46. /**
  47. * Constructs a new <tt>HashMap</tt> with the same mappings as the
  48. * specified <tt>Map</tt>. The <tt>HashMap</tt> is created with
  49. * default load factor (0.75) and an initial capacity sufficient to
  50. * hold the mappings in the specified <tt>Map</tt>.
  51. *
  52. * @param m the map whose mappings are to be placed in this map
  53. * @throws NullPointerException if the specified map is null
  54. */
  55. public HashMap(Map<? extends K, ? extends V> m) {
  56. // 使用默认的负载因子 0.75
  57. this.loadFactor = DEFAULT_LOAD_FACTOR;
  58. putMapEntries(m, false);
  59. }
  60.  
  61. /**
  62. * Implements Map.putAll and Map constructor
  63. *
  64. * @param m the map
  65. * @param evict false when initially constructing this map, else
  66. * true (relayed to method afterNodeInsertion).
  67. */
  68. final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
  69. int s = m.size();
  70. if (s > 0) {
  71. if (table == null) { // pre-size,说明还没有初始化,进行阈值的预设定
  72. float ft = ((float)s / loadFactor) + 1.0F;
  73. int t = ((ft < (float)MAXIMUM_CAPACITY) ?
  74. (int)ft : MAXIMUM_CAPACITY);
  75. if (t > threshold)
  76. threshold = tableSizeFor(t); // 大于等于指定容量且最小 的 2^n
  77. }
  78. else if (s > threshold)
  79. resize(); // 先进行一次扩容
  80. for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
  81. K key = e.getKey();
  82. V value = e.getValue();
  83. putVal(hash(key), key, value, false, evict); // 内部还会检查是否需要扩容
  84. }
  85. }
  86. }

三、HashMap 的 put 操作

  put 操作的源码如下:

  1. /**
  2. * Associates the specified value with the specified key in this map.
  3. * If the map previously contained a mapping for the key, the old
  4. * value is replaced.
  5. *
  6. * @param key key with which the specified value is to be associated
  7. * @param value value to be associated with the specified key
  8. * @return the previous value associated with <tt>key</tt>, or
  9. * <tt>null</tt> if there was no mapping for <tt>key</tt>.
  10. * (A <tt>null</tt> return can also indicate that the map
  11. * previously associated <tt>null</tt> with <tt>key</tt>.)
  12. */
  13. public V put(K key, V value) {
  14. return putVal(hash(key), key, value, false, true);
  15. }
  16.  
  17. /**
  18. * Implements Map.put and related methods
  19. *
  20. * @param hash hash for key
  21. * @param key the key
  22. * @param value the value to put
  23. * @param onlyIfAbsent if true, don't change existing value
  24. * onlyIfAbsent 为 true 时表示不修改已存在的(key 对应的)value
  25. * @param evict if false, the table is in creation mode.
  26. * @return previous value, or null if none
  27. */
  28. final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
  29. boolean evict) {
  30. Node<K,V>[] tab; Node<K,V> p; int n, i;
  31. // 因为前面构造器都没有对数组 table 进行初始化,因此第一次进行put操作时需要进行扩容
  32. // 由于 table 本身为 null,最终也只是新建大小为默认容量 16 的数组而已
  33. if ((tab = table) == null || (n = tab.length) == 0)
  34. n = (tab = resize()).length;
  35. // 当前 key 对应的具体数组下标,如果对应数组元素为 null,则直接初始化 Node 元素并设置即可
  36. if ((p = tab[i = (n - 1) & hash]) == null)
  37. tab[i] = newNode(hash, key, value, null);
  38. else { // 说明该下标位置存在相关的元素数据
  39. Node<K,V> e; K k;
  40. // 数组对应位置的元素的 key 与 put 操作的 key “相等”
  41. if (p.hash == hash &&
  42. ((k = p.key) == key || (key != null && key.equals(k))))
  43. e = p;
  44. // 否则需要判断是链表还是红黑树来执行 put 操作
  45. // 红黑树节点则按照红黑树的插值方法进行
  46. else if (p instanceof TreeNode)
  47. e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
  48. else {
  49. // 执行到这里说明数组的该位置是一个链表
  50. for (int binCount = 0; ; ++binCount) {
  51. if ((e = p.next) == null) {
  52. // 插入到链表的最后位置
  53. p.next = newNode(hash, key, value, null);
  54. // binCount 为 7 时触发红黑树转化,明显此时0-6已经有节点了,
  55. // 再加上原来的 tab[i](相当于 -1),新插入的是链表的第9个位置
  56. if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
  57. treeifyBin(tab, hash);
  58. break;
  59. }
  60. // put 操作的 key 与链表中的该位置的 key “相等”
  61. if (e.hash == hash &&
  62. ((k = e.key) == key || (key != null && key.equals(k))))
  63. // 说明在链表中存在并找到了与 key 一致的节点
  64. break;
  65. p = e;
  66. }
  67. }
  68. // 存在旧的 key 与要 put 的 key 一致,考虑是否进行值覆盖,然后返回旧值
  69. if (e != null) { // existing mapping for key
  70. V oldValue = e.value;
  71. if (!onlyIfAbsent || oldValue == null)
  72. e.value = value;
  73. afterNodeAccess(e);
  74. return oldValue;
  75. }
  76. }
  77. // 记录修改次数
  78. ++modCount;
  79. // 超过阈值,则进行扩容
  80. if (++size > threshold)
  81. resize();
  82. afterNodeInsertion(evict);
  83. return null;
  84. }

 四、HashMap 的扩容

  HashMap扩容的过程也就是内部数组的扩容,源码如下:

  1. /**
  2. * Initializes or doubles table size. If null, allocates in
  3. * accord with initial capacity target held in field threshold.
  4. * Otherwise, because we are using power-of-two expansion, the
  5. * elements from each bin must either stay at same index, or move
  6. * with a power of two offset in the new table.
  7. * 初始化 或者 倍增扩容
  8. * @return the table
  9. */
  10. final Node<K,V>[] resize() {
  11. Node<K,V>[] oldTab = table;
  12. int oldCap = (oldTab == null) ? 0 : oldTab.length;
  13. int oldThr = threshold;
  14. int newCap, newThr = 0;
  15. if (oldCap > 0) {
  16. if (oldCap >= MAXIMUM_CAPACITY) {
  17. threshold = Integer.MAX_VALUE;
  18. return oldTab;
  19. }
  20. // 将数组大小扩大一倍
  21. else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
  22. oldCap >= DEFAULT_INITIAL_CAPACITY)
  23. newThr = oldThr << 1; // double threshold 阈值扩大一倍
  24. }
  25. // 有进行初始化容量的设定时会设置 threshold,此时的第一次 put 操作进入这里
  26. else if (oldThr > 0) // initial capacity was placed in threshold
  27. newCap = oldThr;
  28. else { // zero initial threshold signifies using defaults
  29. // 没有指定初始容量的 new HashMap(),第一次 put 操作进入这里
  30. newCap = DEFAULT_INITIAL_CAPACITY;
  31. newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
  32. }
  33. if (newThr == 0) {
  34. float ft = (float)newCap * loadFactor;
  35. newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
  36. (int)ft : Integer.MAX_VALUE);
  37. }
  38. threshold = newThr;
  39. // 初始化数组或者创建容量翻倍的数组
  40. @SuppressWarnings({"rawtypes","unchecked"})
  41. Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
  42. table = newTab;
  43. if (oldTab != null) { // 初始化的则会跳过这里直接返回
  44. // 遍历数组进行节点的迁移
  45. for (int j = 0; j < oldCap; ++j) {
  46. Node<K,V> e;
  47. if ((e = oldTab[j]) != null) {
  48. oldTab[j] = null;
  49. // 该位置是单个节点元素,不是数组也不是红黑树,则直接迁移
  50. if (e.next == null)
  51. newTab[e.hash & (newCap - 1)] = e;
  52. else if (e instanceof TreeNode) // 红黑树时的节点迁移
  53. ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
  54. else { // preserve order
  55. // 链表情况下的迁移
  56. // 将链表拆成两个链表,放到新的数组中,并且保留原来的先后顺序
  57. // loHead、loTail 对应一条链表,hiHead、hiTail 则对应另一条链表
  58. Node<K,V> loHead = null, loTail = null;
  59. Node<K,V> hiHead = null, hiTail = null;
  60. Node<K,V> next;
  61. do {
  62. next = e.next;
  63. if ((e.hash & oldCap) == 0) {
  64. if (loTail == null)
  65. loHead = e;
  66. else
  67. loTail.next = e;
  68. loTail = e;
  69. }
  70. else {
  71. if (hiTail == null)
  72. hiHead = e;
  73. else
  74. hiTail.next = e;
  75. hiTail = e;
  76. }
  77. } while ((e = next) != null);
  78. if (loTail != null) {
  79. loTail.next = null;
  80. // 第一条链表
  81. newTab[j] = loHead;
  82. }
  83. if (hiTail != null) {
  84. hiTail.next = null;
  85. // 第二条链表的新的位置是 j + oldCap,也比较好理解
  86. newTab[j + oldCap] = hiHead;
  87. }
  88. }
  89. }
  90. }
  91. }
  92. return newTab;
  93. }

五、HashMap 的 get 操作

  get 操作比较直接,流程大致如下:

  1. 计算 key 的 hash 值,根据 hash 找到对应的数组下标即 (table.length - 1) & hash;
  2. 判断对应下标处的节点元素是否正好是要寻找,如是即返回;否,继续下一步;
  3. 如果是红黑树,则用红黑树的方法获取数据;
  4. 如果是链表,则按照链表的方式寻找相应的节点;
  5. 找不到的,返回 null。
  1. /**
  2. * Returns the value to which the specified key is mapped,
  3. * or {@code null} if this map contains no mapping for the key.
  4. *
  5. * <p>More formally, if this map contains a mapping from a key
  6. * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
  7. * key.equals(k))}, then this method returns {@code v}; otherwise
  8. * it returns {@code null}. (There can be at most one such mapping.)
  9. *
  10. * <p>A return value of {@code null} does not <i>necessarily</i>
  11. * indicate that the map contains no mapping for the key; it's also
  12. * possible that the map explicitly maps the key to {@code null}.
  13. * The {@link #containsKey containsKey} operation may be used to
  14. * distinguish these two cases.
  15. *
  16. * @see #put(Object, Object)
  17. */
  18. public V get(Object key) {
  19. Node<K,V> e;
  20. return (e = getNode(hash(key), key)) == null ? null : e.value;
  21. }
  22. /**
  23. * Implements Map.get and related methods
  24. *
  25. * @param hash hash for key
  26. * @param key the key
  27. * @return the node, or null if none
  28. */
  29. final Node<K,V> getNode(int hash, Object key) {
  30. Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
  31. if ((tab = table) != null && (n = tab.length) > 0 &&
  32. (first = tab[(n - 1) & hash]) != null) {
  33. // 第一个节点的判断
  34. if (first.hash == hash && // always check first node
  35. ((k = first.key) == key || (key != null && key.equals(k))))
  36. return first;
  37. if ((e = first.next) != null) {
  38. // 红黑树的走法
  39. if (first instanceof TreeNode)
  40. return ((TreeNode<K,V>)first).getTreeNode(hash, key);
  41. // 链表的遍历
  42. do {
  43. if (e.hash == hash &&
  44. ((k = e.key) == key || (key != null && key.equals(k))))
  45. return e;
  46. } while ((e = e.next) != null);
  47. }
  48. }
  49. return null;
  50. }

六、HashMap 的 remove 操作

  源码走起:

  1. /**
  2. * Removes the mapping for the specified key from this map if present.
  3. *
  4. * @param key key whose mapping is to be removed from the map
  5. * @return the previous value associated with <tt>key</tt>, or
  6. * <tt>null</tt> if there was no mapping for <tt>key</tt>.
  7. * (A <tt>null</tt> return can also indicate that the map
  8. * previously associated <tt>null</tt> with <tt>key</tt>.)
  9. */
  10. public V remove(Object key) {
  11. Node<K,V> e;
  12. return (e = removeNode(hash(key), key, null, false, true)) == null ?
  13. null : e.value;
  14. }
  15.  
  16. /**
  17. * Implements Map.remove and related methods
  18. *
  19. * @param hash hash for key
  20. * @param key the key
  21. * @param value the value to match if matchValue, else ignored
  22. * @param matchValue if true only remove if value is equal
  23. * @param movable if false do not move other nodes while removing
  24. * @return the node, or null if none
  25. */
  26. final Node<K,V> removeNode(int hash, Object key, Object value,
  27. boolean matchValue, boolean movable) {
  28. Node<K,V>[] tab; Node<K,V> p; int n, index;
  29. if ((tab = table) != null && (n = tab.length) > 0 &&
  30. (p = tab[index = (n - 1) & hash]) != null) { // 先找到对应的数组下标
  31. Node<K,V> node = null, e; K k; V v;
  32. // 总是先判断第一个是否是要找的
  33. if (p.hash == hash &&
  34. ((k = p.key) == key || (key != null && key.equals(k))))
  35. node = p;
  36. else if ((e = p.next) != null) {
  37. // 红黑树的找法
  38. if (p instanceof TreeNode)
  39. node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
  40. else { // 链表的找法
  41. do {
  42. if (e.hash == hash &&
  43. ((k = e.key) == key ||
  44. (key != null && key.equals(k)))) {
  45. node = e;
  46. break;
  47. }
  48. p = e;
  49. } while ((e = e.next) != null);
  50. }
  51. }
  52. if (node != null && (!matchValue || (v = node.value) == value ||
  53. (value != null && value.equals(v)))) {
  54. // 红黑树按照红黑树的方式移除
  55. if (node instanceof TreeNode)
  56. ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
  57. // 刚好是数组节点的移除
  58. else if (node == p)
  59. tab[index] = node.next;
  60. // 链表的移除
  61. else
  62. p.next = node.next;
  63. // 记录 修改次数 和元素节点的 实际个数
  64. ++modCount;
  65. --size;
  66. afterNodeRemoval(node);
  67. return node;
  68. }
  69. }
  70. return null;
  71. }

七、参考

  Java8 中 HashMap 的相关基本操作源码介绍,这里也可以直接参考【Java7/8中的 HashMap 和 ConcurrentHashMap 全解析,介绍得还是挺详细的。

备注:关于红黑树和ConcurrentHashMap,有待后续的进一步研究。

Java8集合框架——HashMap源码分析的更多相关文章

  1. Java8集合框架——LinkedList源码分析

    java.util.LinkedList 本文的主要目录结构: 一.LinkedList的特点及与ArrayList的比较 二.LinkedList的内部实现 三.LinkedList添加元素 四.L ...

  2. Java8集合框架——LinkedHashMap源码分析

    本文的结构如下: 一.LinkedHashMap 的 Javadoc 文档注释和简要说明 二.LinkedHashMap 的内部实现:一些扩展属性和构造函数 三.LinkedHashMap 的 put ...

  3. Java8集合框架——ArrayList源码分析

    java.util.ArrayList 以下为主要介绍要点,从 Java 8 出发: 一.ArrayList的特点概述 二.ArrayList的内部实现:从内部属性和构造函数说起 三.ArrayLis ...

  4. Java8集合框架——HashSet源码分析

    本文的目录结构: 一.HashSet 的 Javadoc 文档注释和简要说明 二.HashSet 的内部实现:内部属性和构造函数 三.HashSet 的 add 操作和扩容 四.HashSet 的 r ...

  5. Java8集合框架——LinkedHashSet源码分析

    本文的目录结构如下: 一.LinkedHashSet 的 Javadoc 文档注释和简要说明 二.LinkedHashSet 的内部实现:构造函数 三.LinkedHashSet 的 add 操作和 ...

  6. 【JAVA集合】HashMap源码分析(转载)

    原文出处:http://www.cnblogs.com/chenpi/p/5280304.html 以下内容基于jdk1.7.0_79源码: 什么是HashMap 基于哈希表的一个Map接口实现,存储 ...

  7. Java基础-集合框架-ArrayList源码分析

    一.JDK中ArrayList是如何实现的 1.先看下ArrayList从上而下的层次图: 说明: 从图中可以看出,ArrayList只是最下层的实现类,集合的规则和扩展都是AbstractList. ...

  8. 死磕 java集合之HashMap源码分析

    欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. 简介 HashMap采用key/value存储结构,每个key对应唯一的value,查询和修改 ...

  9. Java集合之HashMap源码分析

    以下源码均为jdk1.7 HashMap概述 HashMap是基于哈希表的Map接口的非同步实现. 提供所有可选的映射操作, 并允许使用null值和null健. 此类不保证映射的顺序. 需要注意的是: ...

随机推荐

  1. 118.django中表单的使用方式

    表单 HTML中的表单: 从前端来说,表单就是用来将数据提交给服务器的,不管后台使用的是django还是php等其他的语言.只要把input标签放在form标签中,然后再添加一个提交的按钮,就可以将i ...

  2. vue的自定义

    自定义组件 组件是可以被复用的页面的零件,其实就是一个插件,只是在vue里叫组件 先看看别人的组件 vant element Mint iView 去试试上面的组件,都是有脚手架版和直接引入使用的版本 ...

  3. python实现进程的三种方式及其区别

    在python中有三种方式用于实现进程 多进程中, 每个进程中所有数据( 包括全局变量) 都各有拥有⼀份, 互不影响 1.fork()方法 ret = os.fork() if ret == 0: # ...

  4. Flask—核心对象app初步理解

    前言 flask的核心对象是Flask,它定义了flask框架对于http请求的整个处理逻辑.随着服务器被启动,app被创建并初始化,那么具体的过程是这样的呢? flask的核心程序就两个: 1.we ...

  5. <深入理解redis>读书笔记

    chapter2 键管理与数据结构 对大多数redis解决方案而言,键的命名设计至关重要.对于管理来说,内存消耗和redis性能都与数据结构设计相关.所以对开发者而言,最好有数据结构的命名文档规范. ...

  6. Charles抓包(HTTP)

    一.电脑抓包: 安装Charles,打开Charles即可 二.手机抓包: 设置手机WiFi配置代理即可:(确保电脑和手机在同一个网络) 三.拦截请求: 四.修改请求/返回: 打上断点后,刷新页面,在 ...

  7. 数据结构——KMP(串)

    KMP一个非常经典的字符串模式匹配算法,虽然网上有很多kmp算法的博客,但是为了更好的理解kmp我还是自己写了一遍(这个kmp的字符串存储是基于堆的(heap),和老师说的定长存储略有不同,字符串索引 ...

  8. c++输出哈夫曼编码

    #include<iostream> #include<string> using namespace std; struct huffTree { int parent; i ...

  9. JavaWeb开发校园二手平台项目 源码

    开发环境: Windows操作系统开发工具:MyEclipse/Eclipse + JDK+ Tomcat + MySQL 数据库 项目简介: JAVAWEB校园二手平台项目,基本功能包括:个人信息. ...

  10. Django——整体结构/MVT设计模式

    MVT设计模式 Models      封装数据库,对数据进行增删改查; Views        进行业务逻辑的处理 Templates  进行前端展示 前端展示看到的是模板  -->  发起 ...