本文的结构如下:

一、LinkedHashMap 的 Javadoc 文档注释和简要说明

  先膜拜下 LinkedHashMap 的 Javadoc,只能说很佩服,这文档注释把 LinkedHashMap 的主要特点都罗列出来了。看懂这注释,然后再对照源码,可以理解个七七八八八,也不会奇怪说各路总结那么多,都是哪来的。以下是 Javadoc 的几点摘抄:

  • LinkedHashMap 是 Map 接口的 hash table 和 linked list 实现类,内部所有节点维护了双链表,迭代顺序可预测,默认按照插入顺序进行迭代输出(已存在的 k 重新 put 不影响顺序,因为 m.containsKey(k) 会先返回 true ),这种特性对于需要有序的 Map 参数来说很有用,而且效率优于 TreeMap。
  • LinkedHashMap 还提供了构造器用于指定按照访问顺序进行迭代输出,即按照最近最少访问到最近访问的访问顺序:from least-recently accessed to most-recently (access-order)。这种特性适合做 LRU 缓存(least-recently used cache),即继承 LinkedHashMap ,重写 removeEldestEntry(Map.Entry) 方法来指定什么时候移除的策略。
  • LinkedHashMap 继承了 HashMap,基本操作(add, contains and remove)可以认为是O(1),因需要维护双链表,性能可能会略低于 HashMap,但是有一个例外:LinkedHashMap 的迭代只与实际大小有关(毕竟可以依靠双链表进行迭代),而 HashMap 的迭代则与容量有关,性能会相对低于 LinkedHashMap。
  • 同样不适合多线程操作,需要额外进行同步,比如使用 Collections.synchronizedMap 。
  • 迭代器也是 fail-fast,而且并不保证出现有并发修改就百分百抛出 ConcurrentModificationException,而是尽可能检查到,因此只适用于检测 bug(抛出 ConcurrentModificationException 说明有问题,但是没有抛出来不能说明没问题)。

  可以看出,LinkedHashMap 有 2个 主要用途:

  • 有序的 HashMap
  • LRU cache

LinkedHashMap 的 Javadoc:

  1. /**
  2. * <p>Hash table and linked list implementation of the <tt>Map</tt> interface,
  3. * with predictable iteration order. This implementation differs from
  4. * <tt>HashMap</tt> in that it maintains a doubly-linked list running through
  5. * all of its entries. This linked list defines the iteration ordering,
  6. * which is normally the order in which keys were inserted into the map
  7. * (<i>insertion-order</i>). Note that insertion order is not affected
  8. * if a key is <i>re-inserted</i> into the map. (A key <tt>k</tt> is
  9. * reinserted into a map <tt>m</tt> if <tt>m.put(k, v)</tt> is invoked when
  10. * <tt>m.containsKey(k)</tt> would return <tt>true</tt> immediately prior to
  11. * the invocation.)
  12. *
  13. * <p>This implementation spares its clients from the unspecified, generally
  14. * chaotic ordering provided by {@link HashMap} (and {@link Hashtable}),
  15. * without incurring the increased cost associated with {@link TreeMap}. It
  16. * can be used to produce a copy of a map that has the same order as the
  17. * original, regardless of the original map's implementation:
  18. * <pre>
  19. * void foo(Map m) {
  20. * Map copy = new LinkedHashMap(m);
  21. * ...
  22. * }
  23. * </pre>
  24. * This technique is particularly useful if a module takes a map on input,
  25. * copies it, and later returns results whose order is determined by that of
  26. * the copy. (Clients generally appreciate having things returned in the same
  27. * order they were presented.)
  28. *
  29. * <p>A special {@link #LinkedHashMap(int,float,boolean) constructor} is
  30. * provided to create a linked hash map whose order of iteration is the order
  31. * in which its entries were last accessed, from least-recently accessed to
  32. * most-recently (<i>access-order</i>). This kind of map is well-suited to
  33. * building LRU caches. Invoking the {@code put}, {@code putIfAbsent},
  34. * {@code get}, {@code getOrDefault}, {@code compute}, {@code computeIfAbsent},
  35. * {@code computeIfPresent}, or {@code merge} methods results
  36. * in an access to the corresponding entry (assuming it exists after the
  37. * invocation completes). The {@code replace} methods only result in an access
  38. * of the entry if the value is replaced. The {@code putAll} method generates one
  39. * entry access for each mapping in the specified map, in the order that
  40. * key-value mappings are provided by the specified map's entry set iterator.
  41. * <i>No other methods generate entry accesses.</i> In particular, operations
  42. * on collection-views do <i>not</i> affect the order of iteration of the
  43. * backing map.
  44. *
  45. * <p>The {@link #removeEldestEntry(Map.Entry)} method may be overridden to
  46. * impose a policy for removing stale mappings automatically when new mappings
  47. * are added to the map.
  48. *
  49. * <p>This class provides all of the optional <tt>Map</tt> operations, and
  50. * permits null elements. Like <tt>HashMap</tt>, it provides constant-time
  51. * performance for the basic operations (<tt>add</tt>, <tt>contains</tt> and
  52. * <tt>remove</tt>), assuming the hash function disperses elements
  53. * properly among the buckets. Performance is likely to be just slightly
  54. * below that of <tt>HashMap</tt>, due to the added expense of maintaining the
  55. * linked list, with one exception: Iteration over the collection-views
  56. * of a <tt>LinkedHashMap</tt> requires time proportional to the <i>size</i>
  57. * of the map, regardless of its capacity. Iteration over a <tt>HashMap</tt>
  58. * is likely to be more expensive, requiring time proportional to its
  59. * <i>capacity</i>.
  60. *
  61. * <p>A linked hash map has two parameters that affect its performance:
  62. * <i>initial capacity</i> and <i>load factor</i>. They are defined precisely
  63. * as for <tt>HashMap</tt>. Note, however, that the penalty for choosing an
  64. * excessively high value for initial capacity is less severe for this class
  65. * than for <tt>HashMap</tt>, as iteration times for this class are unaffected
  66. * by capacity.
  67. *
  68. * <p><strong>Note that this implementation is not synchronized.</strong>
  69. * If multiple threads access a linked hash map concurrently, and at least
  70. * one of the threads modifies the map structurally, it <em>must</em> be
  71. * synchronized externally. This is typically accomplished by
  72. * synchronizing on some object that naturally encapsulates the map.
  73. *
  74. * If no such object exists, the map should be "wrapped" using the
  75. * {@link Collections#synchronizedMap Collections.synchronizedMap}
  76. * method. This is best done at creation time, to prevent accidental
  77. * unsynchronized access to the map:<pre>
  78. * Map m = Collections.synchronizedMap(new LinkedHashMap(...));</pre>
  79. *
  80. * A structural modification is any operation that adds or deletes one or more
  81. * mappings or, in the case of access-ordered linked hash maps, affects
  82. * iteration order. In insertion-ordered linked hash maps, merely changing
  83. * the value associated with a key that is already contained in the map is not
  84. * a structural modification. <strong>In access-ordered linked hash maps,
  85. * merely querying the map with <tt>get</tt> is a structural modification.
  86. * </strong>)
  87. *
  88. * <p>The iterators returned by the <tt>iterator</tt> method of the collections
  89. * returned by all of this class's collection view methods are
  90. * <em>fail-fast</em>: if the map is structurally modified at any time after
  91. * the iterator is created, in any way except through the iterator's own
  92. * <tt>remove</tt> method, the iterator will throw a {@link
  93. * ConcurrentModificationException}. Thus, in the face of concurrent
  94. * modification, the iterator fails quickly and cleanly, rather than risking
  95. * arbitrary, non-deterministic behavior at an undetermined time in the future.
  96. *
  97. * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
  98. * as it is, generally speaking, impossible to make any hard guarantees in the
  99. * presence of unsynchronized concurrent modification. Fail-fast iterators
  100. * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
  101. * Therefore, it would be wrong to write a program that depended on this
  102. * exception for its correctness: <i>the fail-fast behavior of iterators
  103. * should be used only to detect bugs.</i>
  104. *
  105. * <p>The spliterators returned by the spliterator method of the collections
  106. * returned by all of this class's collection view methods are
  107. * <em><a href="Spliterator.html#binding">late-binding</a></em>,
  108. * <em>fail-fast</em>, and additionally report {@link Spliterator#ORDERED}.
  109. *
  110. * <p>This class is a member of the
  111. * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  112. * Java Collections Framework</a>.
  113. *
  114. * @implNote
  115. * The spliterators returned by the spliterator method of the collections
  116. * returned by all of this class's collection view methods are created from
  117. * the iterators of the corresponding collections.
  118. *
  119. * @param <K> the type of keys maintained by this map
  120. * @param <V> the type of mapped values
  121. *
  122. * @author Josh Bloch
  123. * @see Object#hashCode()
  124. * @see Collection
  125. * @see Map
  126. * @see HashMap
  127. * @see TreeMap
  128. * @see Hashtable
  129. * @since 1.4
  130. */

二、LinkedHashMap 的内部实现:一些扩展属性和构造函数

  LinkedHashMap 继承了 HashMap,这里重点说下 LinkedHashMap 在内部属性和构造函数方面扩展的部分。

1、扩展的属性和内部类

  可以初步看出内部的一些变化,比如增加了首节点和尾节点的记录,内部节点元素增加了 before 和 after 节点。这些都是维持双链表需要用到的。另外就是 accessOrder ,用于指定是否按照 访问顺序(设置为 true) 排序(默认 false 是插入顺序)。

  1. /**
  2. * HashMap.Node subclass for normal LinkedHashMap entries.
  3. * LinkedHashMap 的内部节点实现类,这里增加了 before 和 after 节点,用于维护 doubly-linked list
  4. * 这里继承了 HashMap.Node ,保证新节点的类型一致,都是 HashMap.Node
  5. */
  6. static class Entry<K,V> extends HashMap.Node<K,V> {
  7. Entry<K,V> before, after;
  8. Entry(int hash, K key, V value, Node<K,V> next) {
  9. super(hash, key, value, next);
  10. }
  11. }
  12.  
  13. /**
  14. * The head (eldest) of the doubly linked list.
  15. * 首节点元素(最早插入/最近最早访问过的)
  16. */
  17. transient LinkedHashMap.Entry<K,V> head;
  18.  
  19. /**
  20. * The tail (youngest) of the doubly linked list.
  21. * 尾节点元素(最晚插入/最近访问的)
  22. */
  23. transient LinkedHashMap.Entry<K,V> tail;
  24.  
  25. /**
  26. * The iteration ordering method for this linked hash map: <tt>true</tt>
  27. * for access-order, <tt>false</tt> for insertion-order.
  28. * 迭代器的顺序控制
  29. * true:根据访问顺序
  30. * false:默认场景,根据插入顺序
  31. * @serial
  32. */
  33. final boolean accessOrder;

2、构造函数

  和 HashMap 构造函数的差别主要是 accessOrder 的设置。

  1. /**
  2. * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
  3. * with the specified initial capacity and load factor.
  4. *
  5. * 指定 初始容量 和 负载因子 ,同时默认为 插入顺序
  6. * @param initialCapacity the initial capacity
  7. * @param loadFactor the load factor
  8. * @throws IllegalArgumentException if the initial capacity is negative
  9. * or the load factor is nonpositive
  10. */
  11. public LinkedHashMap(int initialCapacity, float loadFactor) {
  12. super(initialCapacity, loadFactor);
  13. accessOrder = false;
  14. }
  15.  
  16. /**
  17. * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
  18. * with the specified initial capacity and a default load factor (0.75).
  19. *
  20. * 指定 初始容量 ,默认负载因子 0.75,同时默认为 插入顺序
  21. * @param initialCapacity the initial capacity
  22. * @throws IllegalArgumentException if the initial capacity is negative
  23. */
  24. public LinkedHashMap(int initialCapacity) {
  25. super(initialCapacity);
  26. accessOrder = false;
  27. }
  28.  
  29. /**
  30. * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
  31. * with the default initial capacity (16) and load factor (0.75).
  32. *
  33. * 空构造函数,默认初始容量 16,默认负载因子 0.75,同时默认为 插入顺序
  34. */
  35. public LinkedHashMap() {
  36. super();
  37. accessOrder = false;
  38. }
  39.  
  40. /**
  41. * Constructs an insertion-ordered <tt>LinkedHashMap</tt> instance with
  42. * the same mappings as the specified map. The <tt>LinkedHashMap</tt>
  43. * instance is created with a default load factor (0.75) and an initial
  44. * capacity sufficient to hold the mappings in the specified map.
  45. *
  46. * 通过指定 Map 构造默认为 插入顺序 的 LinkedHashMap
  47. * @param m the map whose mappings are to be placed in this map
  48. * @throws NullPointerException if the specified map is null
  49. */
  50. public LinkedHashMap(Map<? extends K, ? extends V> m) {
  51. super();
  52. accessOrder = false;
  53. putMapEntries(m, false);
  54. }
  55.  
  56. /**
  57. * Constructs an empty <tt>LinkedHashMap</tt> instance with the
  58. * specified initial capacity, load factor and ordering mode.
  59. *
  60. * 指定 初始容量、负载因子、排序模式
  61. * @param initialCapacity the initial capacity
  62. * @param loadFactor the load factor
  63. * @param accessOrder the ordering mode - <tt>true</tt> for
  64. * access-order, <tt>false</tt> for insertion-order
  65. * @throws IllegalArgumentException if the initial capacity is negative
  66. * or the load factor is nonpositive
  67. */
  68. public LinkedHashMap(int initialCapacity,
  69. float loadFactor,
  70. boolean accessOrder) {
  71. super(initialCapacity, loadFactor);
  72. this.accessOrder = accessOrder;
  73. }

三、LinkedHashMap 的 put 操作和扩容

  put 操作直接继承自 HashMap,由于 LinkedHashMap 会涉及到双向链表的处理,这里有几个 注意点/改动点 需要说明下:

1、重写新节点创建函数 Node<K,V> newNode(int hash, K key, V value, Node<K,V> e),维护双链表

  LinkedHashMap 的节点会有双向链表,因此在这里进行了处理,很明显,新节点即使最后访问也是最新插入的,直接就丢到最后去没毛病,因此链接到了链表最后/最新处。

  1. // 创建新节点 并将 新节点 链接 到最后
  2. Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
  3. LinkedHashMap.Entry<K,V> p =
  4. new LinkedHashMap.Entry<K,V>(hash, key, value, e);
  5. linkNodeLast(p); // 将 新节点 链接 到最后
  6. return p;
  7. }
  8.  
  9. // link at the end of list
  10. // 将 新节点 链接 到最后
  11. private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
  12. LinkedHashMap.Entry<K,V> last = tail;
  13. tail = p;
  14. if (last == null)
  15. head = p;
  16. else {
  17. p.before = last;
  18. last.after = p;
  19. }
  20. }

2、HashMap 中留下来的三个回调函数, LinkedHashMap 都进行了重写

  put 操作中有使用到的是 afterNodeAccess(Node<K,V> p) 和 afterNodeInsertion(boolean evict)。

  • afterNodeAccess(Node<K,V> p) :k 存在的时候进行的操作。如果是根据访问控制顺序,需要将访问到的节点的链接到最后去;
  • afterNodeInsertion(boolean evict) :k 不存在的时候进行的操作。 LRU cache 中可以进行实际的移除节点操作
  1. // Callbacks to allow LinkedHashMap post-actions
  2. void afterNodeAccess(Node<K,V> p) { } // 访问节点后需要进行的操作,如果指定了根据访问顺序控制,则在这里将节点挪到最后
  3. void afterNodeInsertion(boolean evict) { } // 插入节点后需要进行的操作,比如 LRU cache 中移除最早的节点
  4. void afterNodeRemoval(Node<K,V> p) { } // 移除指定节点

  在 LinkedHashMap 中的实现如下:

  1. // 移除 e 节点元素后的操作,对于 HashMap ,removeNode 函数已经是移除了节点,这里是 LinkedHashMap 处理节点中和双向链表有关的的 before 和 after
  2. void afterNodeRemoval(Node<K,V> e) { // unlink
  3. LinkedHashMap.Entry<K,V> p =
  4. (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
  5. // 移除 e 节点本身的链接
  6. p.before = p.after = null;
  7. if (b == null) // 重置 e 节点上一个节点的 after 链接
  8. head = a;
  9. else
  10. b.after = a;
  11. if (a == null) // 重置 e 节点下一个节点的 before 链接
  12. tail = b;
  13. else
  14. a.before = b;
  15. }
  16.  
  17. // 是否移除最早插入/访问的节点元素
  18. void afterNodeInsertion(boolean evict) { // possibly remove eldest
  19. LinkedHashMap.Entry<K,V> first;
  20. // 最简单的 LRU cache 其实就是重写 removeEldestEntry 什么时候返回 true 的逻辑(比如超过容量限制),然后移除最早插入/访问的节点
  21. if (evict && (first = head) != null && removeEldestEntry(first)) {
  22. K key = first.key;
  23. removeNode(hash(key), key, null, false, true);
  24. }
  25. }
  26.  
  27. // 节点访问后是否将节点挪到最后
  28. void afterNodeAccess(Node<K,V> e) { // move node to last
  29. LinkedHashMap.Entry<K,V> last;
  30. if (accessOrder && (last = tail) != e) {
  31. LinkedHashMap.Entry<K,V> p =
  32. (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
  33. p.after = null;
  34. if (b == null) // 重置 e 节点上一个节点的 after 链接
  35. head = a;
  36. else
  37. b.after = a;
  38. if (a != null) // 重置 e 节点下一个节点的 before 链接
  39. a.before = b;
  40. else
  41. last = b;
  42. if (last == null) // 只有一个 e 节点的场景
  43. head = p;
  44. else {
  45. p.before = last; // 把 e 节点挪到最后
  46. last.after = p;
  47. }
  48. tail = p; // 尾节点处理
  49. ++modCount;
  50. }
  51. }

  这里再看看 removeEldestEntry(Map.Entry<K,V> eldest),这个方法是实现 LRU cache 的关键所在,文档注释中其实已经写明了简要应用,也就是检查 Map 的实际大小是否 大于 规定的容量,超过就是返回true,需要进行节点移除,保证集合不超过规定的上限。

  1. /**
  2. * Returns <tt>true</tt> if this map should remove its eldest entry.
  3. * This method is invoked by <tt>put</tt> and <tt>putAll</tt> after
  4. * inserting a new entry into the map. It provides the implementor
  5. * with the opportunity to remove the eldest entry each time a new one
  6. * is added. This is useful if the map represents a cache: it allows
  7. * the map to reduce memory consumption by deleting stale entries.
  8. *
  9. * <p>Sample use: this override will allow the map to grow up to 100
  10. * entries and then delete the eldest entry each time a new entry is
  11. * added, maintaining a steady state of 100 entries.
  12. * <pre>
  13. * private static final int MAX_ENTRIES = 100;
  14. *
  15. * protected boolean removeEldestEntry(Map.Entry eldest) {
  16. * return size() &gt; MAX_ENTRIES;
  17. * }
  18. * </pre>
  19. *
  20. * <p>This method typically does not modify the map in any way,
  21. * instead allowing the map to modify itself as directed by its
  22. * return value. It <i>is</i> permitted for this method to modify
  23. * the map directly, but if it does so, it <i>must</i> return
  24. * <tt>false</tt> (indicating that the map should not attempt any
  25. * further modification). The effects of returning <tt>true</tt>
  26. * after modifying the map from within this method are unspecified.
  27. *
  28. * <p>This implementation merely returns <tt>false</tt> (so that this
  29. * map acts like a normal map - the eldest element is never removed).
  30. *
  31. * @param eldest The least recently inserted entry in the map, or if
  32. * this is an access-ordered map, the least recently accessed
  33. * entry. This is the entry that will be removed it this
  34. * method returns <tt>true</tt>. If the map was empty prior
  35. * to the <tt>put</tt> or <tt>putAll</tt> invocation resulting
  36. * in this invocation, this will be the entry that was just
  37. * inserted; in other words, if the map contains a single
  38. * entry, the eldest entry is also the newest.
  39. * @return <tt>true</tt> if the eldest entry should be removed
  40. * from the map; <tt>false</tt> if it should be retained.
  41. */
  42. protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
  43. return false;
  44. }

3、还有一个比较骚的操作就是 HashMap 内部 红黑树节点 TreeNode 是直接继承 LinkedHashMap.Entry,因此这方面的 红黑树转化、扩容等等基本上可以说是无缝对接。

  1. static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {...}

  红黑树转化和扩容其实只是涉及到内部节点的挪动,双向链表是不用改动的,因此不需要进行操作。

四、LinkedHashMap 的 get 操作

  增加了 afterNodeAccess(Node<K,V> p) 的调用,对于访问顺序控制 LinkedHashMap,需要将访问的节点挪到最后去。其他的和 HashMap 一样。

  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. public V get(Object key) {
  17. Node<K,V> e;
  18. if ((e = getNode(hash(key), key)) == null)
  19. return null;
  20. if (accessOrder)
  21. afterNodeAccess(e); // 增加访问节点后需要进行的操作,如果指定了根据访问顺序控制,则在这里将节点挪到最后
  22. return e.value;
  23. }

五、LinkedHashMap 的 remove 操作

  节点的移除使用的是 HashMap 的 remove(Object key) ,移除其实是一样的,只是 LinkedHashMap 在最后需要处理双链表,这里使用的是扩展了 afterNodeRemoval(Node<K,V> p) 来进行处理。这个方法在 LinkedHashMap 的实现可以翻看本文前面的介绍。

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

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

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

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

    java.util.HashMap 本文目录: 一.HashMap 的特点概述和说明 二.HashMap 的内部实现:从内部属性和构造函数说起 三.HashMap 的 put 操作 四.HashMap ...

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

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

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

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

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

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

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

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

  7. 死磕 java集合之LinkedHashMap源码分析

    欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. 简介 LinkedHashMap内部维护了一个双向链表,能保证元素按插入的顺序访问,也能以访问 ...

  8. Java集合之LinkedHashMap源码分析

    概述 HashMap是无序的, 即put的顺序与遍历顺序不保证一样. LinkedHashMap是HashMap的一个子类, 它通过重写父类的相关方法, 实现自己的功能. 它保留插入的顺序. 如果需要 ...

  9. 死磕 java集合之LinkedHashSet源码分析

    问题 (1)LinkedHashSet的底层使用什么存储元素? (2)LinkedHashSet与HashSet有什么不同? (3)LinkedHashSet是有序的吗? (4)LinkedHashS ...

随机推荐

  1. JS 循环赋值

    var x_world_map_tiles = 100; var y_world_map_tiles = 100; var world_map_array = []; for (i=0; i<= ...

  2. Java8 HashMap详解

    Java8 HashMap Java8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑树,所以其由 数组+链表+红黑树 组成. 根据 Java7 HashMap 的介绍,我们知道,查找的 ...

  3. JMeter配置JDBC测试SQL Server/MySQL/ORACLE

    一.配置SQL Server 1.下载sql驱动,将sqljdbc4.jar放到JMeter安装目录/lib下. 2.启动JMeter,右键添加->配置文件->JDBC Connectio ...

  4. python中提取位图信息(AttributeError: module 'struct' has no attribute 'unstack')

    前言 今天这篇博文有点意思,它是从一个例子出发,从而体现出在编程中的种种细节和一些知识点的运用.和从前一样,我是人,离成神还有几十万里,所以无可避免的出现不严谨的地方甚至错误,请酌情阅读. 0x00 ...

  5. 新建Django 项目完整流程

    1) 在桌面或者其他文件 新建项目名称 (mkdir 新建文件夹) 2)进入文件夹  pipenv --python3(用命令提示粘贴复制, 自己这样写经常有问题) 3) 启动虚拟环境  pipenv ...

  6. 吴裕雄--天生自然MySQL学习笔记:MySQL 安装

    所有平台的 MySQL 下载地址为: MySQL 下载:https://dev.mysql.com/downloads/mysql/ 注意:安装过程我们需要通过开启管理员权限来安装,否则会由于权限不足 ...

  7. vbox虚拟机vdi文件用VMware打开

    转自:https://blog.51cto.com/dahui09/1863486 方法一: 使用VirtualBox 自带的VBoxManage来进行格式转换: 1.安装VBoxManage 2.使 ...

  8. Codeforces 1296E2. String Coloring (hard version)

    这道题和HDU1257一模一样,一开始窝都用贪心直接解,没法理解为什么求一个最长下降序列,直到看了巨巨的题解,先给出一个定理,Dilworth's theorem,离散学不好,补题两行泪,该定理是说, ...

  9. 运算符 Operator 及优先级

    算数运算符 + - * / ** % /表示自然除,结果是浮点数.//为整除.python2.x版本/和//都是整除. 位运算符 & | ~ ^ << >> <& ...

  10. 5.8 Nginx 常用功能的配置