最近在整理JAVA 基础知识,从jdk源码入手,今天就jdk中 java.util包下集合类进行理解

先看图

从类图结构可以了解 java.util包下的2个大类:

  1、Collecton:可以理解为主要存放的是单个对象

  2、Map:可以理解为主要存储key-value类型的对象

一、Collection

  Collection继承了Iterate接口,Iterate用于集合内迭代器抽象接口,其子类均实现接口中方法,看下ArrayList下实现:

  1. /**
  2. * Returns an iterator over the elements in this list in proper sequence.
  3. *
  4. * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
  5. *
  6. * @return an iterator over the elements in this list in proper sequence
  7. */
  8. public Iterator<E> iterator() {
  9. return new Itr(); // 返回内部类实例
  10. }
  11.  
  12. /**
  13. * An optimized version of AbstractList.Itr
  14. */
  15. private class Itr implements Iterator<E> {
  16. int cursor; // index of next element to return 指向下一个位置索引id
  17. int lastRet = -1; // index of last element returned; -1 if no such 指向上一个位置索引id
  18. int expectedModCount = modCount;
  19.  
  20. public boolean hasNext() {
  21. return cursor != size;
  22. }
  23.  
  24. @SuppressWarnings("unchecked")
  25. public E next() {
  26. checkForComodification();
  27. int i = cursor;
  28. if (i >= size)
  29. throw new NoSuchElementException();
  30. Object[] elementData = ArrayList.this.elementData;
  31. if (i >= elementData.length)
  32. throw new ConcurrentModificationException();
  33. cursor = i + 1;
  34. return (E) elementData[lastRet = i];
  35. }
  36.  
  37. public void remove() {
  38. if (lastRet < 0)
  39. throw new IllegalStateException();
  40. checkForComodification();
  41.  
  42. try {
  43. ArrayList.this.remove(lastRet);
  44. cursor = lastRet;
  45. lastRet = -1;
  46. expectedModCount = modCount;
  47. } catch (IndexOutOfBoundsException ex) {
  48. throw new ConcurrentModificationException();
  49. }
  50. }
  51.  
  52. @Override
  53. @SuppressWarnings("unchecked")
  54. public void forEachRemaining(Consumer<? super E> consumer) {
  55. Objects.requireNonNull(consumer);
  56. final int size = ArrayList.this.size;
  57. int i = cursor;
  58. if (i >= size) {
  59. return;
  60. }
  61. final Object[] elementData = ArrayList.this.elementData;
  62. if (i >= elementData.length) {
  63. throw new ConcurrentModificationException();
  64. }
  65. while (i != size && modCount == expectedModCount) {
  66. consumer.accept((E) elementData[i++]);
  67. }
  68. // update once at end of iteration to reduce heap write traffic
  69. cursor = i;
  70. lastRet = i - 1;
  71. checkForComodification();
  72. }
  73.  
  74. final void checkForComodification() {
  75. if (modCount != expectedModCount)
  76. throw new ConcurrentModificationException();
  77. }
  78. }

1、List

  特点:有序结果、顺序遍历、索引、允许有重复值

  (1) ArrayList

    以上特点实现:

  1. transient Object[] elementData; // List内部存储对象数组结果
  2.  
  3. public boolean add(E e) {
  4. ensureCapacityInternal(size + 1); // Increments modCount!!
  5. elementData[size++] = e;
  6. return true;
  7. }
  8. // 添加对象时先识别是否越界,没有越界则数组对象当前索引值的下一个添
  9. // 添加对象时,不识别重复,所以有序允许重复值
  10.  
  11. /**
  12. * Removes all of the elements from this list. The list will
  13. * be empty after this call returns.
  14. */
  15. public void clear() {
  16. modCount++;
  17.  
  18. // clear to let GC do its work
  19. for (int i = 0; i < size; i++)
  20. elementData[i] = null;
  21.  
  22. size = 0;
  23. }
  24. // 清空List时顺序遍历值置为null

public E get(int index) {
  rangeCheck(index);

  return elementData(index);
}

E elementData(int index) {
  return (E) elementData[index];
}

其中 remove方法 :

  1. public E remove(int index) { // 按索引删除对象
  2. rangeCheck(index); // 校验输入索引id是否越界,若越界则抛出运行时异常 IndexOutOfBoundsException
  3.  
  4. modCount++;
  5. E oldValue = elementData(index);
  6.  
  7. int numMoved = size - index - 1; // 定位到索引的下一位
  8. if (numMoved > 0)
  9. System.arraycopy(elementData, index+1, elementData, index,
  10. numMoved); //调用native方法实现数组位置左移
  11. elementData[--size] = null; // clear to let GC do its work
  12.      // 末尾元素置空
  13. return oldValue;
  14. }
  15.  
  16. public boolean remove(Object o) {// 按对象删除
  17. if (o == null) {
  18. for (int index = 0; index < size; index++)
  19. if (elementData[index] == null) {
  20. fastRemove(index);
  21. return true;
  22. }
  23. } else {
  24. for (int index = 0; index < size; index++)
  25. if (o.equals(elementData[index])) { // 识别对象相等使用equals方法,使用时注意重写equals方法
  26. fastRemove(index);
  27. return true;
  28. }
  29. }
  30. return false;
  31. }
  32.  
  33. /*
  34. * Private remove method that skips bounds checking and does not
  35. * return the value removed.
  36. */
  37. private void fastRemove(int index) {
  38. modCount++; // 删除元素时,modCount值变更
  39. int numMoved = size - index - 1;
  40. if (numMoved > 0)
  41. System.arraycopy(elementData, index+1, elementData, index,
  42. numMoved);
  43. elementData[--size] = null; // clear to let GC do its work
  44. }

可以看到ArrayList中对数组进行,操作时常用到System.arraycopy

  1. java.lang.System
    public static native void arraycopy(Object src, int srcPos,
  2. Object dest, int destPos,
  3. int length);

还有在 java.util.Arrays下数组copy方法,最终也是调用System.arraycopy方法

  1. public static <T> T[] copyOf(T[] original, int newLength) {
  2. return (T[]) copyOf(original, newLength, original.getClass());
  3. }
  4.  
  5. public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
  6. @SuppressWarnings("unchecked")
  7. T[] copy = ((Object)newType == (Object)Object[].class)
  8. ? (T[]) new Object[newLength]
  9. : (T[]) Array.newInstance(newType.getComponentType(), newLength);
  10. System.arraycopy(original, 0, copy, 0,
  11. Math.min(original.length, newLength));
  12. return copy;
  13. }

示例:

  1. package jdk.array;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.Arrays;
  5. import java.util.Iterator;
  6.  
  7. public class ArrayListTest1 {
  8.  
  9. public static void main(String[] args) {
  10.  
  11. ArrayList<String> l1 = new ArrayList<>();
  12. l1.add("s1");
  13. l1.add("s2");
  14. l1.add("s1");
  15. l1.add("s2");
  16. l1.add("s2");
  17. l1.add("s2");
  18. l1.add("s3");
  19. l1.add("s3");
  20. l1.add("s3");
  21.  
  22. // 使用容器迭代器遍历List
  23. Iterator<String> iterator = l1.iterator();
  24. while (iterator.hasNext()) {
  25. String str = iterator.next();
  26. if ("s1".equals(str)) {
  27. iterator.remove(); // 迭代器内部方法remove()
  28. }
  29. }
  30. System.out.println(Arrays.toString(l1.toArray()));
  31.  
  32. // 使用 for循环遍历List
  33. for(int i = 0 ; i < l1.size(); i++) {
  34. if ("s2".equals(l1.get(1))) {
  35. l1.remove(i);
  36. i--;
  37. }
  38. }
  39. System.out.println(Arrays.toString(l1.toArray()));
  40.  
  41. // 使用foreach遍历List
  42. for (String str : l1) {
  43. if ("s3".equals(str)) {
  44. l1.remove(str); // ArrayList内部方法remove(Object)
  45. }
  46. }
  47. System.out.println(Arrays.toString(l1.toArray()));
  48. }
  49.  
  50. }

可以看到出现异常:ConcurrentModificationException,出现该异常原因是:

“快速失败”也就是fail-fast,它是Java集合的一种错误检测机制。当创建Iterator后,在Iterator使用还没有结束时,改变(删除或增添新项)集合元素就会出现上面的错误

看看ArrayList的排序方法:sort(Comparator<? super E> c)

  1. public void sort(Comparator<? super E> c) {
  2. final int expectedModCount = modCount;
  3. Arrays.sort((E[]) elementData, 0, size, c);
  4. if (modCount != expectedModCount) {
  5. throw new ConcurrentModificationException();
  6. }
  7. modCount++;
  8. }
  9.  
  10. public static <T> void sort(T[] a, int fromIndex, int toIndex,
  11. Comparator<? super T> c) {
  12. if (c == null) {
  13. sort(a, fromIndex, toIndex);
  14. } else {
  15. rangeCheck(a.length, fromIndex, toIndex);
  16. if (LegacyMergeSort.userRequested)
  17. legacyMergeSort(a, fromIndex, toIndex, c);
  18. else
  19. TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
  20. }
  21. }

示例:

  1. package jdk.array;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.Arrays;
  5. import java.util.Comparator;
  6. import java.util.Iterator;
  7.  
  8. public class ArrayListTest2 {
  9.  
  10. public static void main(String[] args) {
  11.  
  12. ArrayList<String> l1 = new ArrayList<>();
  13. l1.add("s1");
  14. l1.add("s2");
  15. l1.add("s1");
  16. l1.add("s2");
  17. l1.add("s2");
  18. l1.add("s2");
  19. l1.add("s3");
  20. l1.add("s3");
  21. l1.add("s3");
  22.  
  23. System.out.println(Arrays.toString(l1.toArray()));
  24.  
  25. l1.sort(null);
  26.  
  27. System.out.println(Arrays.toString(l1.toArray()));
  28.  
  29. l1.sort(new Comparator() {
  30.  
  31. @Override
  32. public int compare(Object o1, Object o2) {
  33.  
  34. return -((String) o1).compareTo((String) o2);
  35. }
  36.  
  37. });
  38.  
  39. System.out.println(Arrays.toString(l1.toArray()));
  40.  
  41. }
  42.  
  43. }

  (2)LinkedList

  1. public class LinkedList<E>
  2. extends AbstractSequentialList<E>
  3. implements List<E>, Deque<E>, Cloneable, java.io.Serializable
  4. // 实现了Deque接口,可以做队列使用
  5.  
  6. /**
  7. * Pointer to first node.
  8. * Invariant: (first == null && last == null) ||
  9. * (first.prev == null && first.item != null)
  10. */
  11. transient Node<E> first;
  12.  
  13. /**
  14. * Pointer to last node.
  15. * Invariant: (first == null && last == null) ||
  16. * (last.next == null && last.item != null)
  17. */
  18. transient Node<E> last;
  19.  
  20. /**
  21. * Constructs an empty list.
  22. */
  23. public LinkedList() {
  24. }
  25.  
  26. // 集合对象存储结构,通过当前节点的前后节点,维护顺序集合(双向链表结构)
  27. private static class Node<E> {
  28. E item;
  29. Node<E> next;
  30. Node<E> prev;
  31.  
  32. Node(Node<E> prev, E element, Node<E> next) {
  33. this.item = element;
  34. this.next = next;
  35. this.prev = prev;
  36. }
  37. }

以上为 LinkedList的内部存储结构,以Node存储。

在看下集合元素插入、删除及获取方法实现:

  1. public boolean add(E e) {
  2. linkLast(e);
  3. return true;
  4. }
  5.  
  6. /**
  7. * Links e as last element.
  8. */
  9. void linkLast(E e) {
  10. final Node<E> l = last; // 保存最后个节点
  11. final Node<E> newNode = new Node<>(l, e, null);// 新增节点
  12. last = newNode; // 将新节点置为最后节点
  13. if (l == null)
  14. first = newNode;
  15. else
  16. l.next = newNode;
  17. size++;
  18. modCount++;
  19. }
  20.  
  21. public E remove() {
  22. return removeFirst(); // 去掉首节点
  23. }
  24.  
  25. public E removeFirst() {
  26. final Node<E> f = first;
  27. if (f == null)
  28. throw new NoSuchElementException();
  29. return unlinkFirst(f);
  30. }
  31.  
  32. private E unlinkFirst(Node<E> f) {
  33. // assert f == first && f != null;
  34. final E element = f.item;
  35. final Node<E> next = f.next;
  36. f.item = null;
  37. f.next = null; // help GC
  38. first = next;
  39. if (next == null)
  40. last = null;
  41. else
  42. next.prev = null;
  43. size--;
  44. modCount++;
  45. return element;
  46. }
  47.  
  48. // 入栈方法
  49. public void push(E e) {
  50. addFirst(e);
  51. }
  52. // 出栈方法
  53. public E pop() {
  54. return removeFirst();
  55. }
  56.  
  57. // 入队
  58. public boolean offer(E e) {
  59. return add(e);
  60. }
  61. public boolean add(E e) {
  62. linkLast(e);
  63. return true;
  64. }
  65. // 出队
  66. public E poll() {
  67. final Node<E> f = first;
  68. return (f == null) ? null : unlinkFirst(f);
  69. }
  70.  
  71. //随机访问集合对象
  72. public E get(int index) {
  73. checkElementIndex(index);
  74. return node(index).item;
  75. }
  76.  
  77. /**
  78. * Returns the (non-null) Node at the specified element index.
  79. */
  80. Node<E> node(int index) {
  81. // assert isElementIndex(index);
  82. // 识别 index id离首节点近还是尾节点近,减少遍历
  83. if (index < (size >> 1)) {
  84. Node<E> x = first;
  85. for (int i = 0; i < index; i++) // 0(i)
  86. x = x.next;
  87. return x;
  88. } else {
  89. Node<E> x = last;
  90. for (int i = size - 1; i > index; i--) // 0(i)
  91. x = x.prev;
  92. return x;
  93. }
  94. }

通过以上源码理解 ArrayList 和 LinkedList 区别类似数据结构中 数组及链表结构区别 ,新增、删除 和 随机访问存在 效率上的差别:

ArrayList是最常用的集合,其内部实现是一个数组,ArrayList的大小是可以动态扩充的。对于元素的随机访问效率高,其访问的时间复杂度为O(1),对于数据的插入与删除,从尾部操作效率高,时间复杂度和随机访问一样是O(1),若是从头部操作则效率会比较低,因为从头部插入或删除时需要移动后面所有元素,其时间复杂度为O(n-i)(n表示元素个数,i表示元素位置)

LinkList对于随机访问效率是比较低的,因为它需要从头开始索引,所以其时间复杂度为O(i)。但是对于元素的增删,LinkList效率高,因为只需要修改前后指针即可,其时间复杂度为O(1)

  (3)Vector

    与ArrayList类型,内部也是使用数据来存储对象,但是线程安全的,因为实现方法重写的时候,全部加上了同步关键字:synchronized;(一般不建议使用,性能消耗)

  (4)Stack

  1. public
  2. class Stack<E> extends Vector<E> {
  3. /**
  4. * Creates an empty Stack.
  5. */
  6. public Stack() {
  7. }

  2、Queue

  遵循FIFO(先入先出规则),内部出栈入栈方法,主要区别在于是否是阻塞入队或出队

  3、Set 

  1. public class HashSet<E>
  2. extends AbstractSet<E>
  3. implements Set<E>, Cloneable, java.io.Serializable
  4.  
  5. /**
  6. * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  7. * default initial capacity (16) and load factor (0.75).
  8. */
  9. public HashSet() {
  10. map = new HashMap<>();
  11. }
  12.  
  13. // Set 集合对象存储在 Map的 key中
  14. public boolean contains(Object o) {
  15. return map.containsKey(o);
  16. }
  17.  
  18. // 添加对象到Set集合中
  19. public boolean add(E e) {
  20. return map.put(e, PRESENT)==null;
  21. }
  22. // 删除Set集合中对象
  23. public boolean remove(Object o) {
  24. return map.remove(o)==PRESENT;
  25. }

实际Set集合的实现依赖于Map的实现,通过Map的 key值唯一性来实现

二、Map

  1、HashMap:基于Map接口实现、允许null 键值、无序、非同步

  一起看下HashMap的实现

  1. // map 内部对象链表存储结构
  2. static class Node<K,V> implements Map.Entry<K,V> {
  3. final int hash;
  4. final K key;
  5. V value;
  6. Node<K,V> next; // 下一节点
  7.  
  8. Node(int hash, K key, V value, Node<K,V> next) {
  9. this.hash = hash;
  10. this.key = key;
  11. this.value = value;
  12. this.next = next;
  13. }
  14.  
  15. public final K getKey() { return key; }
  16. public final V getValue() { return value; }
  17. public final String toString() { return key + "=" + value; }
  18. // 重写hashCode方法
  19. public final int hashCode() {
  20. return Objects.hashCode(key) ^ Objects.hashCode(value);
  21. }
  22.  
  23. public final V setValue(V newValue) {
  24. V oldValue = value;
  25. value = newValue;
  26. return oldValue;
  27. }
  28. // 重写 equals方法
  29. public final boolean equals(Object o) {
  30. if (o == this)
  31. return true;
  32. if (o instanceof Map.Entry) {
  33. Map.Entry<?,?> e = (Map.Entry<?,?>)o;
  34. if (Objects.equals(key, e.getKey()) &&
  35. Objects.equals(value, e.getValue()))
  36. return true;
  37. }
  38. return false;
  39. }
  40. }
  41.  
  42. transient Node<K,V>[] table; // 用数组保存多条链表的首节点
  43.  
  44. // 获取 key所对应的存储JNode的 value值
  45. public V get(Object key) {
  46. Node<K,V> e;
  47. return (e = getNode(hash(key), key)) == null ? null : e.value;
  48. }
  49. // 识别是否存在key所对应的 Node
  50. public boolean containsKey(Object key) {
  51. return getNode(hash(key), key) != null;
  52. }
  1. // map 内部对象链表存储结构
  2. static class Node<K,V> implements Map.Entry<K,V> {
  3. final int hash;
  4. final K key;
  5. V value;
  6. Node<K,V> next; // 下一节点
  7.  
  8. Node(int hash, K key, V value, Node<K,V> next) {
  9. this.hash = hash;
  10. this.key = key;
  11. this.value = value;
  12. this.next = next;
  13. }
  14.  
  15. public final K getKey() { return key; }
  16. public final V getValue() { return value; }
  17. public final String toString() { return key + "=" + value; }
  18. // 重写hashCode方法
  19. public final int hashCode() {
  20. return Objects.hashCode(key) ^ Objects.hashCode(value);
  21. }
  22.  
  23. public final V setValue(V newValue) {
  24. V oldValue = value;
  25. value = newValue;
  26. return oldValue;
  27. }
  28. // 重写 equals方法
  29. public final boolean equals(Object o) {
  30. if (o == this)
  31. return true;
  32. if (o instanceof Map.Entry) {
  33. Map.Entry<?,?> e = (Map.Entry<?,?>)o;
  34. if (Objects.equals(key, e.getKey()) &&
  35. Objects.equals(value, e.getValue()))
  36. return true;
  37. }
  38. return false;
  39. }
  40. }
  41.  
  42. transient Node<K,V>[] table; // 用数组保存多条链表的首节点
  43.  
  44. // 获取 key所对应的存储JNode的 value值
  45. public V get(Object key) {
  46. Node<K,V> e;
  47. return (e = getNode(hash(key), key)) == null ? null : e.value;
  48. }
  49. // 识别是否存在key所对应的 Node
  50. public boolean containsKey(Object key) {
  51. return getNode(hash(key), key) != null;
  52. }
  1. // 插入 对象
  2. public V put(K key, V value) {
  3. return putVal(hash(key), key, value, false, true);
  4. }
  5.  
  6. // 调用的内部方法,
  7. final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
  8. boolean evict) {
  9. // tab 为map内首节点集合
  10. Node<K,V>[] tab; Node<K,V> p; int n, i;
  11. // 先识别table是否为空,为空则初始化,hashmap内存存储延迟加载在这里体现
  12. if ((tab = table) == null || (n = tab.length) == 0)
  13. n = (tab = resize()).length;
  14. // 通过hash值以长度做按位与,识别读取元素的存储在tab中的位置
  15. if ((p = tab[i = (n - 1) & hash]) == null)
  16. // 若tab所在链表首节点为空,则直接构造新节点
  17. tab[i] = newNode(hash, key, value, null);
  18. else {
  19. // tab所在链表首节点不为空,则遍历p所在链表或红黑树,找到可以存储的位置
  20. Node<K,V> e; K k;
  21. if (p.hash == hash &&
  22. ((k = p.key) == key || (key != null && key.equals(k))))
  23. e = p;
  24. else if (p instanceof TreeNode)
  25. e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
  26. else {
  27. for (int binCount = 0; ; ++binCount) {
  28. if ((e = p.next) == null) {
  29. p.next = newNode(hash, key, value, null);
  30. if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
  31. treeifyBin(tab, hash);
  32. break;
  33. }
  34. if (e.hash == hash &&
  35. ((k = e.key) == key || (key != null && key.equals(k))))
  36. break;
  37. p = e;
  38. }
  39. }
  40. if (e != null) { // existing mapping for key
  41. V oldValue = e.value;
  42. if (!onlyIfAbsent || oldValue == null)
  43. e.value = value;
  44. afterNodeAccess(e);
  45. return oldValue;
  46. }
  47. }
  48. ++modCount;
  49. if (++size > threshold)
  50. resize();
  51. afterNodeInsertion(evict);
  52. return null;
  53. }

可以看到,在HashMap中存储的结构下, Node类型的数组保存头部节点(单链表)或根节点(红黑树),先以 Node的key的hash值与数组长度做位与运算(hash碰撞),初始

时使用单链表存储新插入对象(newNode),当链表长度超过8时,会将链表结构转为红黑树结构存储(treeifyBin方法)

  1. final void treeifyBin(Node<K,V>[] tab, int hash) {
  2. int n, index; Node<K,V> e;
  3. if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
  4. resize();
  5. else if ((e = tab[index = (n - 1) & hash]) != null) {
  6. // 找到需要转换的 单链表 e,遍历单链表,转换为TreeNode,保存前后节点关系
  7. TreeNode<K,V> hd = null, tl = null;
  8. do {
  9. TreeNode<K,V> p = replacementTreeNode(e, null);
  10. if (tl == null)
  11. hd = p;
  12. else {
  13. p.prev = tl;
  14. tl.next = p;
  15. }
  16. tl = p;
  17. } while ((e = e.next) != null);
  18. //让桶的第一个元素指向新建的红黑树头结点,以后这个桶里的元素就是红黑树而不是链表了
  19. if ((tab[index] = hd) != null)
  20. hd.treeify(tab);
  21. }
  22. }

先将单链表转换为 treenode,在调用 treeify方法构造红黑树

  2、LinkedHashMap

   继承HashMap,HashMap是无序集合,而LinkedHashMap为有序集合

  1. public class LinkedHashMap<K,V>
  2. extends HashMap<K,V>
  3. implements Map<K,V>

 构造LinkedHashMap.EntreyNode<K,V> 继承 HashMap.Node<K,V> 实现双向链表

  1. static class Entry<K,V> extends HashMap.Node<K,V> {
  2. Entry<K,V> before, after; // before 保存前置节点,after保存后置节点
  3. Entry(int hash, K key, V value, Node<K,V> next) {
  4. super(hash, key, value, next);
  5. }
  6. }
  7.  
  8. /**
  9. * The head (eldest) of the doubly linked list.
  10. */
  11. transient LinkedHashMap.Entry<K,V> head; // 头节点
  12.  
  13. /**
  14. * The tail (youngest) of the doubly linked list.
  15. */
  16. transient LinkedHashMap.Entry<K,V> tail; // 尾部节点
  17.  
  18. // 重写HashMap的 创建新节点方法
  19. Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
  20. LinkedHashMap.Entry<K,V> p =
  21. new LinkedHashMap.Entry<K,V>(hash, key, value, e);
  22. linkNodeLast(p); // 将新节点放到尾部节点,从而保证顺序
  23. return p;
  24. }
  25.  
  26. // link at the end of list
  27. private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
  28. LinkedHashMap.Entry<K,V> last = tail;
  29. tail = p;
  30. if (last == null)
  31. head = p;
  32. else {
  33. p.before = last;
  34. last.after = p;
  35. }
  36. }

  3、TreeMap

  TreeMap直接使用红黑树结构存储集合元素,根据键 做排序,排序规则按内部 comparator 对象的实例对象的排序规则,若comparator为空,则按自然排序

  1. public class TreeMap<K,V>
  2. extends AbstractMap<K,V>
  3. implements NavigableMap<K,V>, Cloneable, java.io.Serializable
  4. {
  5. /**
  6. * The comparator used to maintain order in this tree map, or
  7. * null if it uses the natural ordering of its keys.
  8. *
  9. * @serial
  10. */
  11. private final Comparator<? super K> comparator; // 对象比较接口
  12.  
  13. private transient Entry<K,V> root; // 根节点

root的实现逻辑为 TreeMap.Entrey<K,V> 继承 Map.Entrey<K,V> 实现 ,与HashMap.TreeNode<K,V>实现类似

  1. static final class Entry<K,V> implements Map.Entry<K,V> {
  2. K key;
  3. V value;
  4. Entry<K,V> left;
  5. Entry<K,V> right;
  6. Entry<K,V> parent;
  7. boolean color = BLACK;

所以TreeMap put和get方法就是以键先进行红黑树的查找后操作

  4、HashTable

  HashTable和HashMap数据结构类似,主要区别为HashTable中操作集合元素对象的方法都加上了 同步关键字(synchronized), 所以说线程安全的及集合

【java基础之jdk源码】集合类的更多相关文章

  1. 【java基础之jdk源码】Object

    最新在整体回归下java基础薄弱环节,以下为自己整理笔记,若有理解错误,请批评指正,谢谢. java.lang.Object为java所有类的基类,所以一般的类都可用重写或直接使用Object下方法, ...

  2. Jdk源码-集合类主要原理和解析

    写在前面 熟悉Jdk原理的重要性不言而喻,作为Java开发者或者面试者,了解其实现原理也显得更为装逼,在Java读书计划我写到了,它是面试中最基础的一部分,所以单独拿出来做个总结,为了更好滴理解和学习 ...

  3. Java基础(八)--String(源码)、StringBuffer、StringBuilder

    String源码:基于jdk1.8 public final class String implements Serializable, Comparable<String>, CharS ...

  4. Java基础try-with-resource语法源码分析

    众所周知,所有被打开的系统资源,比如流.文件或者Socket连接等,都需要被开发者手动关闭,否则随着程序的不断运行,资源泄露将会累积成重大的生产事故. 在Java的江湖中,存在着一种名为finally ...

  5. JDK源码学习笔记——Object

    一.源码解析 public class Object { /** * 一个本地方法,具体是用C(C++)在DLL中实现的,然后通过JNI调用 */ private static native void ...

  6. 从JDK源码角度看java并发的公平性

    JAVA为简化开发者开发提供了很多并发的工具,包括各种同步器,有了JDK我们只要学会简单使用类API即可.但这并不意味着不需要探索其具体的实现机制,本文从JDK源码角度简单讲讲并发时线程竞争的公平性. ...

  7. 一点一点看JDK源码(三)java.util.ArrayList 前偏

    一点一点看JDK源码(三)java.util.ArrayList liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 1.综述 ArrayLi ...

  8. 一点一点看JDK源码(六)java.util.LinkedList前篇之链表概要

    一点一点看JDK源码(六)java.util.LinkedList前篇之链表概要 liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 1.什么 ...

  9. Java是如何实现自己的SPI机制的? JDK源码(一)

    注:该源码分析对应JDK版本为1.8 1 引言 这是[源码笔记]的JDK源码解读的第一篇文章,本篇我们来探究Java的SPI机制的相关源码. 2 什么是SPI机制 那么,什么是SPI机制呢? SPI是 ...

随机推荐

  1. VC创建多级目录

    BOOL ForceCreateDirectory(string strDir)  {    BOOL bRet = FALSE;    //确保以"\"结尾,以创建最后一个目录  ...

  2. 有限状态机(Finite-state machine)

    var menu = { // 当前状态 currentState: 'hide', // 绑定事件 initialize: function() { var self = this; self.on ...

  3. 前言《iOS网络高级编程:iPhone和iPad的企业应用开发》(书籍学习)

    本书内容: 在客户端设备与服务器之间执行HTTP请求 管理客户端设备与服务器之间的数据负载 处理HTTP请求的错误 保护网络通信 改进网络通信的性能 执行Socket层的通信 实现推送通知 单个设备上 ...

  4. CSS 简介、语法、派生选择器、id 选择器、类选择器、属性选择器

    CSS 概述 CSS 指层叠样式表 (Cascading Style Sheets) 样式定义如何显示 HTML 元素 样式通常存储在样式表中 把样式添加到 HTML 4.0 中,是为了解决内容与表现 ...

  5. 递归求和1到n

    一般的方法 #include<stdio.h> int sum(int n){ if(n==1) return 1; else return n+sum(n-1);} int main(v ...

  6. Unity3D在NGUI中使用mask

    过程是这样的:最近一直想做一个头像的mask效果,后来发现原来unity的mask需要用shader来写,网上找了不少资料,也能实现,不过大多数都是用render texture作为相机投影的text ...

  7. Java Swing paint repaint update 方法的关系

    Java Swing paint repaint update 方法的关系: 参考:http://blog.csdn.net/xiaoliangmeiny/article/details/691665 ...

  8. Vue.js自定义指令的用法与实例

    市面上大多数关于Vue.js自定义指令的文章都在讲语法,很少讲实际的应用场景和用例,以致于即便明白了怎么写,也不知道怎么用.本文不讲语法,就讲自定义指令的用法. 自定义指令是用来操作DOM的.尽管Vu ...

  9. 从零开始学习C#——HelloWorld(一)

    从零开始学习C# 老规矩Hello World 您的第一个程序 visual studio 如何使用就不说了 //编程的开始,Hello World! program in C# using Syst ...

  10. Struct 和 Union 的详细区别

    Union: 共用体 Struct:结构体 两者的区别: 1:共用体和结构体都是由多个不同的数据类型成员组成, 但在任何同一时刻, 共用体只存放一个被选中的成员, 而结构体则存放所有的成员变量. 2: ...