java:容器(Collection)

本篇文章是关于Collection下的List,Set,Queue等的讲解,Map接口的实现类HashMap,LinkedHashMap,ConcurrentHashMap,HashTable的讲解看下面的这篇文章:

Map接口下的实现类讲解

容器相关问题

1 Queue

Queue 与 Deque 的区别

Queue 是单端队列,只能从一端插入元素,另一端删除元素,实现上一般遵循 先进先出(FIFO) 规则。

Queue 扩展了 Collection 的接口,根据 因为容量问题而导致操作失败后处理方式的不同 可以分为两类方法: 一种在操作失败后会抛出异常,另一种则会返回特殊值。

Queue 接口抛出异常返回特殊值
插入队尾add(E e)offer(E e)
删除队首remove()poll()
查询队首元素element()peek()

Deque 是双端队列,在队列的两端均可以插入或删除元素。

Deque 扩展了 Queue 的接口, 增加了在队首和队尾进行插入和删除的方法,同样根据失败后处理方式的不同分为两类:

Deque 接口抛出异常返回特殊值
插入队首addFirst(E e)offerFirst(E e)
插入队尾addLast(E e)offerLast(E e)
删除队首removeFirst()pollFirst()
删除队尾removeLast()pollLast()
查询队首元素getFirst()peekFirst()
查询队尾元素getLast()peekLast()

1.1 priorityQueue

PriorityQueue:Object[] 数组来实现二叉堆

PriorityQueue 是在 JDK1.5 中被引入的, 其与 Queue 的区别在于元素出队顺序是与优先级相关的,即总是优先级最高的元素先出队。

这里列举其相关的一些要点:

  • PriorityQueue 利用了二叉堆的数据结构来实现的,底层使用可变长的数组来存储数据
  • PriorityQueue 通过堆元素的上浮和下沉,实现了在 O(logn) 的时间复杂度内插入元素和删除堆顶元素。
  • PriorityQueue 是非线程安全的,且不支持存储NULLnon-comparable 的对象。
  • PriorityQueue 默认是小顶堆,但可以接收一个Comparator 作为构造参数,从而来自定义元素优先级的先后。

1.1.1 类的常量和字段

// 默认初始化容量
 private static final int DEFAULT_INITIAL_CAPACITY = 11;
 
 /**
      * Priority queue represented as a balanced binary heap: the two
      * children of queue[n] are queue[2*n+1] and queue[2*(n+1)].  The
      * priority queue is ordered by comparator, or by the elements'
      * natural ordering, if comparator is null: For each node n in the
      * heap and each descendant d of n, n <= d.  The element with the
      * lowest value is in queue[0], assuming the queue is nonempty.
      * 底层的数据结构,数组
      */
 transient Object[] queue; // non-private to simplify nested class access
 
 /**
      * The number of elements in the priority queue.
      * 元素的数量
      */
 private int size = 0;
 
 /**
      * The comparator, or null if priority queue uses elements'
      * natural ordering.
      * 比较器
      */
 private final Comparator<? super E> comparator;
 
 /**
      * The number of times this priority queue has been
      * <i>structurally modified</i>.  See AbstractList for gory details.
      * 结构修改的次数
      */
 transient int modCount = 0; // non-private to simplify nested class access
 /**
      * The maximum size of array to allocate.
      * Some VMs reserve some header words in an array.
      * Attempts to allocate larger arrays may result in
      * OutOfMemoryError: Requested array size exceeds VM limit
      * 数组最大容量
      */
 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
```

1.1.2 构造方法

/**
      * Creates a {@code PriorityQueue} with the default initial
      * capacity (11) that orders its elements according to their
      * {@linkplain Comparable natural ordering}.
      */
 public PriorityQueue() {
     // 默认无参构造
     this(DEFAULT_INITIAL_CAPACITY, null);
 }
 
 /**
      * Creates a {@code PriorityQueue} with the specified initial
      * capacity that orders its elements according to their
      * {@linkplain Comparable natural ordering}.
      *
      * @param initialCapacity the initial capacity for this priority queue
      * @throws IllegalArgumentException if {@code initialCapacity} is less
      *         than 1
      */
 public PriorityQueue(int initialCapacity) {
     this(initialCapacity, null);
 }
 
 /**
      * Creates a {@code PriorityQueue} with the default initial capacity and
      * whose elements are ordered according to the specified comparator.
      *
      * @param  comparator the comparator that will be used to order this
      *         priority queue.  If {@code null}, the {@linkplain Comparable
      *         natural ordering} of the elements will be used.
      * @since 1.8
      */
 public PriorityQueue(Comparator<? super E> comparator) {
     this(DEFAULT_INITIAL_CAPACITY, comparator);
 }
 
 /**
      * Creates a {@code PriorityQueue} with the specified initial capacity
      * that orders its elements according to the specified comparator.
      *
      * @param  initialCapacity the initial capacity for this priority queue
      * @param  comparator the comparator that will be used to order this
      *         priority queue.  If {@code null}, the {@linkplain Comparable
      *         natural ordering} of the elements will be used.
      * @throws IllegalArgumentException if {@code initialCapacity} is
      *         less than 1
      */
 public PriorityQueue(int initialCapacity,
                      Comparator<? super E> comparator) {
     // Note: This restriction of at least one is not actually needed,
     // but continues for 1.5 compatibility
     //指定初识容量和比较器的构造方法
     if (initialCapacity < 1)
         throw new IllegalArgumentException();
     // 直接初始化
     this.queue = new Object[initialCapacity];
     this.comparator = comparator;
 }
 
 /**
      * Creates a {@code PriorityQueue} containing the elements in the
      * specified collection.  If the specified collection is an instance of
      * a {@link SortedSet} or is another {@code PriorityQueue}, this
      * priority queue will be ordered according to the same ordering.
      * Otherwise, this priority queue will be ordered according to the
      * {@linkplain Comparable natural ordering} of its elements.
      *
      * @param  c the collection whose elements are to be placed
      *         into this priority queue
      * @throws ClassCastException if elements of the specified collection
      *         cannot be compared to one another according to the priority
      *         queue's ordering
      * @throws NullPointerException if the specified collection or any
      *         of its elements are null
      */
 @SuppressWarnings("unchecked")
 public PriorityQueue(Collection<? extends E> c) {
     // 传入一个集合,那么需要获取它的比较器
     if (c instanceof SortedSet<?>) {
         SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
         this.comparator = (Comparator<? super E>) ss.comparator();
         initElementsFromCollection(ss);
     }
     else if (c instanceof PriorityQueue<?>) {
         PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;
         this.comparator = (Comparator<? super E>) pq.comparator();
         initFromPriorityQueue(pq);
     }
     else {
         this.comparator = null;
         initFromCollection(c);
     }
 }

1.1.3 add方法

public boolean add(E e) {
     return offer(e);
 }
 
 /**
      * Inserts the specified element into this priority queue.
      *
      * @return {@code true} (as specified by {@link Queue#offer})
      * @throws ClassCastException if the specified element cannot be
      *         compared with elements currently in this priority queue
      *         according to the priority queue's ordering
      * @throws NullPointerException if the specified element is null
      */
 public boolean offer(E e) {
     // 添加的元素不能为 null
     if (e == null)
         throw new NullPointerException();
     // 修改结构 + 1
     modCount++;
     // 元素存放的索引位置
     int i = size;
     // 需要扩容
     if (i >= queue.length)
         grow(i + 1);
     size = i + 1;
     // 第一次添加,那么直接添加
     if (i == 0)
         queue[0] = e;
     else
         // 不是第一次添加,那么需要将添加的元素上浮到适合位置
         siftUp(i, e);
     return true;
 }

1.1.4 siftUp方法

上浮操作

/**
      * Inserts item x at position k, maintaining heap invariant by
      * promoting x up the tree until it is greater than or equal to
      * its parent, or is the root.
      *
      * To simplify and speed up coercions and comparisons. the
      * Comparable and Comparator versions are separated into different
      * methods that are otherwise identical. (Similarly for siftDown.)
      * 将项x插入位置k,要保持堆不变性
      *      将x向上提升,直到它大于或等于它的父结点,或者是根结点。(小根堆)
      * @param k the position to fill
      * @param x the item to insert
      */
 private void siftUp(int k, E x) {
     if (comparator != null)
         // 使用自己定义的比较器
         siftUpUsingComparator(k, x);
     else
         // 元素x是实现Comparable接口的
         siftUpComparable(k, x);
 }
 
 /**
      * 根据传入的比较器比较
      */
 private void siftUpUsingComparator(int k, E x) {
     while (k > 0) {
         // 父节点的索引: (k-1) / 2;
         int parent = (k - 1) >>> 1;
         // 父节点
         Object e = queue[parent];
         if (comparator.compare(x, (E) e) >= 0)
             break;
         // k = 父节点索引,继续比较
         queue[k] = e;
         k = parent;
     }
     queue[k] = x;
 }
 /**
      * 根据对象实现的比较方法比较
      */
 private void siftUpComparable(int k, E x) {
     // x是一个可比较对象,内部实现了比较方法
     Comparable<? super E> key = (Comparable<? super E>) x;
     while (k > 0) {
         int parent = (k - 1) >>> 1;
         Object e = queue[parent];
         if (key.compareTo((E) e) >= 0)
             break;
         queue[k] = e;
         k = parent;
     }
     queue[k] = key;
 }

1.1.5 poll方法

/**
      * 返回堆顶元素,并删除
      */
 public E poll() {
     if (size == 0)
         return null;
     // 元素数量 -1
     int s = --size;
     modCount++;
     // 堆顶元素
     E result = (E) queue[0];
     // 堆的最后一位元素
     E x = (E) queue[s];
     // 最后一位元素 = null
     queue[s] = null;
     // 堆中不止一个元素,那么需要下沉
     if (s != 0)
         // 将堆的最后一位元素,放到堆顶,然后下沉
         siftDown(0, x);
     return result;
 }

1.1.6 siftDown方法

下沉方法

/**
      * Inserts item x at position k, maintaining heap invariant by
      * demoting x down the tree repeatedly until it is less than or
      * equal to its children or is a leaf.
      * 将项x插入位置k,保持堆不变性
      *      重复将x降级到树下,直到它小于或等于它的子节点,或者是一个叶节点(小根堆)
      * @param k the position to fill
      * @param x the item to insert
      */
 private void siftDown(int k, E x) {
     if (comparator != null)
         siftDownUsingComparator(k, x);
     else
         siftDownComparable(k, x);
 }
 
 /**
      * 使用Comparator 比较
      */
 private void siftDownUsingComparator(int k, E x) {
     // half:元素数量的一半
     int half = size >>> 1;
     // k 小于 元素数量的一半
     while (k < half) {
         // 左子节点的索引
         int child = (k << 1) + 1;
         // 左子节点
         Object c = queue[child];
         // 右子节点的索引
         int right = child + 1;
         // 右子节点索引合法 并且 右子节点 需要和 左子节点交换
         if (right < size &&
             comparator.compare((E) c, (E) queue[right]) > 0)
             // 要交换的子节点
             c = queue[child = right];
         // 子节点和x比较
         if (comparator.compare(x, (E) c) <= 0)
             break;
         // 继续下沉
         queue[k] = c;
         k = child;
     }
     // 找到了合适的位置
     queue[k] = x;
 }
 
 private void siftDownComparable(int k, E x) {
     Comparable<? super E> key = (Comparable<? super E>)x;
     int half = size >>> 1;        // loop while a non-leaf
     while (k < half) {
         int child = (k << 1) + 1; // assume left child is least
         Object c = queue[child];
         int right = child + 1;
         if (right < size &&
             ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
             c = queue[child = right];
         if (key.compareTo((E) c) <= 0)
             break;
         queue[k] = c;
         k = child;
     }
     queue[k] = key;
 }

1.1.7 grow扩容

/**
      * Increases the capacity of the array.
      * 扩容方法
      * @param minCapacity the desired minimum capacity 需要扩容的最小值
      */
 private void grow(int minCapacity) {
     // 旧容量
     int oldCapacity = queue.length;
     // Double size if small; else grow by 50%
     // 新容量 = (如果旧的容量 < 64 那么就翻倍,否则增加 50%)
     int newCapacity = oldCapacity + ((oldCapacity < 64) ?
                                      (oldCapacity + 2) :
                                      (oldCapacity >> 1));
     // overflow-conscious code
     if (newCapacity - MAX_ARRAY_SIZE > 0)
         newCapacity = hugeCapacity(minCapacity);
     // 拷贝旧数组的数据到新数组
     queue = Arrays.copyOf(queue, newCapacity);
 }

1.2 ArrayDeque

ArrayDeque:Object[] 数组 + 双指针

ArrayDeque 与 LinkedList 的区别

ArrayDequeLinkedList 都实现了 Deque 接口,两者都具有队列的功能,但两者有什么区别呢?

  • ArrayDeque 是基于可变长的数组和双指针来实现,而 LinkedList 则通过链表来实现。
  • ArrayDeque 不支持存储 NULL 数据,但 LinkedList 支持。
  • ArrayDeque 是在 JDK1.6 才被引入的,而LinkedList 早在 JDK1.2 时就已经存在。
  • ArrayDeque 插入时可能存在扩容过程, 不过均摊后的插入操作依然为 O(1)。虽然 LinkedList 不需要扩容,但是每次插入数据时均需要申请新的堆空间,均摊性能相比更慢。

从性能的角度上,选用 ArrayDeque 来实现队列要比 LinkedList 更好。此外,ArrayDeque 也可以用于实现栈

1.2.1 类的常量和字段

/**
      * The array in which the elements of the deque are stored.
      * The capacity of the deque is the length of this array, which is
      * always a power of two. The array is never allowed to become
      * full, except transiently within an addX method where it is
      * resized (see doubleCapacity) immediately upon becoming full,
      * thus avoiding head and tail wrapping around to equal each
      * other.  We also guarantee that all array cells not holding
      * deque elements are always null.
      * 底层数据结构:数组
      */
 transient Object[] elements; // non-private to simplify nested class access
 
 /**
      * The index of the element at the head of the deque (which is the
      * element that would be removed by remove() or pop()); or an
      * arbitrary number equal to tail if the deque is empty.
      * 头指针
      */
 transient int head;
 
 /**
      * The index at which the next element would be added to the tail
      * of the deque (via addLast(E), add(E), or push(E)).
      * 尾指针
      */
 transient int tail;
 
 /**
      * The minimum capacity that we'll use for a newly created deque.
      * Must be a power of 2.
      * 新创建数组的最小容量,数组容量必须是 2 的n次幂
      */
 private static final int MIN_INITIAL_CAPACITY = 8;

1.2.2 构造方法

/**
      * Constructs an empty array deque with an initial capacity
      * sufficient to hold 16 elements.
      */
 public ArrayDeque() {
     // 默认初始容量 16
     elements = new Object[16];
 }
 
 /**
      * Constructs an empty array deque with an initial capacity
      * sufficient to hold the specified number of elements.
      *
      * @param numElements  lower bound on initial capacity of the deque
      */
 public ArrayDeque(int numElements) {
     // 分配数组容量,数组容量必须是2的n次方
     allocateElements(numElements);
 }
 
 /**
      * Constructs a deque containing the elements of the specified
      * collection, in the order they are returned by the collection's
      * iterator.  (The first element returned by the collection's
      * iterator becomes the first element, or <i>front</i> of the
      * deque.)
      *
      * @param c the collection whose elements are to be placed into the deque
      * @throws NullPointerException if the specified collection is null
      */
 public ArrayDeque(Collection<? extends E> c) {
     // 分配数组容量,数组容量必须是2的n次方
     allocateElements(c.size());
     addAll(c);
 }
 /**
      * Allocates empty array to hold the given number of elements.
      * 分配数组来保存给定数量的元素。
      * @param numElements  the number of elements to hold
      */
 private void allocateElements(int numElements) {
     elements = new Object[calculateSize(numElements)];
 }
 // ******  Array allocation and resizing utilities ******
 // 计算数组容量,必须是2 的n次幂
 private static int calculateSize(int numElements) {
     int initialCapacity = MIN_INITIAL_CAPACITY;
     // Find the best power of two to hold elements.
     // Tests "<=" because arrays aren't kept full.
     if (numElements >= initialCapacity) {
         initialCapacity = numElements;
         initialCapacity |= (initialCapacity >>>  1);
         initialCapacity |= (initialCapacity >>>  2);
         initialCapacity |= (initialCapacity >>>  4);
         initialCapacity |= (initialCapacity >>>  8);
         initialCapacity |= (initialCapacity >>> 16);
         initialCapacity++;
 
         if (initialCapacity < 0)   // Too many elements, must back off
             initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
     }
     return initialCapacity;
 }

1.2.3 add方法

public boolean add(E e) {
     addLast(e);
     return true;
 }
 
 
 public void addLast(E e) {
     if (e == null)
         throw new NullPointerException();
     elements[tail] = e;
     // 下面条件满足:tail等于数组长度-1,说明当前数组中已经填充满了元素
     if ( (tail = (tail + 1) & (elements.length - 1)) == head)
         // 扩容
         doubleCapacity();
 }
 
 
 public void addFirst(E e) {
     if (e == null)
         throw new NullPointerException();
     // 第一次从前面添加的时候head = -1 & len-1 = len - 1;
     elements[head = (head - 1) & (elements.length - 1)] = e;
     if (head == tail)
         doubleCapacity();
 }

1.2.4 doubleCapacity方法

/**
      * Doubles the capacity of this deque.  Call only when full, i.e.,
      * when head and tail have wrapped around to become equal.
      * 双队列的容量加倍。只在满时调用,即: 当头部和尾部缠绕成相等的时候。
      */
 private void doubleCapacity() {
     assert head == tail;
     int p = head;
     int n = elements.length;
     // p右边的元素
     int r = n - p; // number of elements to the right of p
     // 新的容量 = 旧容量 * 2
     int newCapacity = n << 1;
     if (newCapacity < 0)
         throw new IllegalStateException("Sorry, deque too big");
     Object[] a = new Object[newCapacity];
     System.arraycopy(elements, p, a, 0, r);
     System.arraycopy(elements, 0, a, r, p);
     elements = a;
     // 重新定值
     head = 0;
     tail = n;
 }

2 List

2.1 ArrayList

2.1.1 类的静态字段和普通字段

// 序列号
 private static final long serialVersionUID = 8683452581122892189L;
 
 /**
      * Default initial capacity.
      * 默认初始容量大小
      */
 private static final int DEFAULT_CAPACITY = 10;
 
 /**
      * Shared empty array instance used for empty instances.
      * 空数组,用于空实例,当实例化的时候传入0,如:new ArrayList<>(0); 那么elementData使用的就是这个
      */
 private static final Object[] EMPTY_ELEMENTDATA = {};
 
 /**
      * Shared empty array instance used for default sized empty instances. We
      * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
      * first element is added.
      * 用于默认大小空实例的共享空数组实例。
      * 我们把它从EMPTY_ELEMENTDATA数组中区分出来,以知道在添加第一个元素时容量需要增加多少。
      * 当实例化的时候没有指定长度,如:new ArrayList<>();
      * 那么elementData使用的就是这个,添加第一个元素的时候容量扩展为DEFAULT_CAPACITY
      */
 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
 
 /**
      * The array buffer into which the elements of the ArrayList are stored.
      * The capacity of the ArrayList is the length of this array buffer. Any
      * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
      * will be expanded to DEFAULT_CAPACITY when the first element is added.
      * 保存ArrayList数据的数组
      */
 transient Object[] elementData; // non-private to simplify nested class access
 
 /**
      * The size of the ArrayList (the number of elements it contains).
      * 数组包含的元素数量
      * @serial
      */
 private int size;
 /**
      * The maximum size of array to allocate.
      * Some VMs reserve some header words in an array.
      * Attempts to allocate larger arrays may result in
      * OutOfMemoryError: Requested array size exceeds VM limit
      * 数组的最大容量
      */
 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

2.1.2 构造方法

/**
      * Constructs an empty list with the specified initial capacity.
      *
      * @param  initialCapacity  the initial capacity of the list
      * @throws IllegalArgumentException if the specified initial capacity
      *         is negative
      * 定义初始容量的构造方法
      */
 public ArrayList(int initialCapacity) {
     if (initialCapacity > 0) {
         this.elementData = new Object[initialCapacity];
     } else if (initialCapacity == 0) {
         this.elementData = EMPTY_ELEMENTDATA;
     } else {
         throw new IllegalArgumentException("Illegal Capacity: "+
                                            initialCapacity);
     }
 }
 
 /**
      * Constructs an empty list with an initial capacity of ten.
      * 无参构造方法
      * DEFAULTCAPACITY_EMPTY_ELEMENTDATA 为0.初始化为10,也就是说初始其实是空数组 当添加第一个元素的时候数组容量才变成10
      */
 public ArrayList() {
     this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
 }
 
 /**
      * Constructs a list containing the elements of the specified
      * collection, in the order they are returned by the collection's
      * iterator.
      *
      * @param c the collection whose elements are to be placed into this list
      * @throws NullPointerException if the specified collection is null
      * 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。
      */
 public ArrayList(Collection<? extends E> c) {
     elementData = c.toArray();
     if ((size = elementData.length) != 0) {
         // c.toArray might (incorrectly) not return Object[] (see 6260652)
         // 如果elementData不是Object类型数据(c.toArray可能返回的不是Object类型的数组所以加上下面的语句用于判断)
         if (elementData.getClass() != Object[].class)
             elementData = Arrays.copyOf(elementData, size, Object[].class);
     } else {
         // replace with empty array.
         this.elementData = EMPTY_ELEMENTDATA;
     }
 }

2.1.3 add方法

add方法 有两个不同参数的方法:

  1. 一个参数,首先判断容量是否足够,如果不够,那么扩容(grow()),然后在已有元素的最后添加元素。
  2. 两个参数(index, e) ,先对index进行界限检查(0<=index <= size),然后检查容量是否足够,不够就扩容,然后将从index索引开始的元素向后移动一位,最后将e添加到index位置。

有一点需要注意的是,如果在实例化的时候,没有指定初识容量,那么ArrayList会在add第一个值的时候,才会初始化容量,calculateCapacity() 这个方法就是用于判断这种情况。

/**
      * Appends the specified element to the end of this list.
      *
      * @param e element to be appended to this list
      * @return <tt>true</tt> (as specified by {@link Collection#add})
      *
      * 常见的增加元素的方法,直接添加到数组的末尾
      */
 public boolean add(E e) {
     // 用于判断容量是否够用,如果不够就会扩容
     ensureCapacityInternal(size + 1);  // Increments modCount!!
     elementData[size++] = e;
     return true;
 }
 /**
      * 首先计算出当前的容量,然后去判断容量是否足够
      * @param minCapacity
      */
 private void ensureCapacityInternal(int minCapacity) {
     ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
 }
 
 /**
      * 该方法是 返回最小的容量,当elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA时,说明是第一次添加元素,那么返回10,需要扩容,如果不是第一次,那么就返回最大的容量。
      * @param elementData
      * @param minCapacity
      * @return
      */
 private static int calculateCapacity(Object[] elementData, int minCapacity) {
     if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
         return Math.max(DEFAULT_CAPACITY, minCapacity);
     }
     return minCapacity;
 }
 
 /**
      * 判断是否需要扩容
      * @param minCapacity
      */
 private void ensureExplicitCapacity(int minCapacity) {
     modCount++;
 
     // overflow-conscious code
     if (minCapacity - elementData.length > 0)
         grow(minCapacity);
 }

add(int index, E e);两个参数的方法

/**
      * Inserts the specified element at the specified position in this
      * list. Shifts the element currently at that position (if any) and
      * any subsequent elements to the right (adds one to their indices).
      *
      * @param index index at which the specified element is to be inserted
      * @param element element to be inserted
      * @throws IndexOutOfBoundsException {@inheritDoc}
      * 在此列表中的指定位置插入指定的元素。
      * 先调用 rangeCheckForAdd 对index进行界限检查;然后调用 ensureCapacityInternal 方法保证capacity足够大;
      *  再将从index开始之后的所有成员后移一个位置;将element插入index位置;最后size加1。
      */
 public void add(int index, E element) {
     // 检查索引是否合法
     rangeCheckForAdd(index);
     // 和一个参数的add方法是一样的
     ensureCapacityInternal(size + 1);  // Increments modCount!!
     // 将index索引之后的元素向后移动一位
     // System.arraycopy(源数组,起始位置,目标数组,起始位置,要复制的长度);
     System.arraycopy(elementData, index, elementData, index + 1,
                      size - index);
     elementData[index] = element;
     size++;
 }
 
 /**
      * A version of rangeCheck used by add and addAll.
      */
 private void rangeCheckForAdd(int index) {
     if (index > size || index < 0)
         throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
 }
 
 // 我们发现 arraycopy 是一个 native 方法,接下来我们解释一下各个参数的具体意义
     /**
     *   复制数组
     * @param src 源数组
     * @param srcPos 源数组中的起始位置
     * @param dest 目标数组
     * @param destPos 目标数组中的起始位置
     * @param length 要复制的数组元素的数量
     */
     public static native void arraycopy(Object src,  int  srcPos,
                                         Object dest, int destPos,
                                         int length);

2.1.4 set方法

该方法:用于替换已有的元素。如果index< 0 那么 会抛出 :java.lang.ArrayIndexOutOfBoundsException: -1

首先验证index的合法性(index<size),然后获取旧的值,最后element替换旧的值,返回旧的值。

/**
      * Replaces the element at the specified position in this list with
      * the specified element.
      *
      * @param index index of the element to replace
      * @param element element to be stored at the specified position
      * @return the element previously at the specified position
      * @throws IndexOutOfBoundsException {@inheritDoc}
      * 替换指定索引上的值,索引必须小于size
      */
 public E set(int index, E element) {
     // 验证索引的合法性,需要注意的是这里的index需要小于size,也就是说set方法,只允许修改已添加元素的索引
     rangeCheck(index);
     // 获取旧的值
     E oldValue = elementData(index);
     elementData[index] = element;
     return oldValue;
 }

2.1.5 grow 方法

首先计算新数组容量,新数组容量 = 旧数组容量 + 旧数组容量 >> 1, 说明每次扩容增加 扩容前容量的一半**(oldCapacity 为偶数就是 1.5 倍,否则是 1.5 倍左右)!** 奇偶不同,比如 :10+10/2 = 15, 33+33/2=49。如果是奇数的话会丢掉小数.

然后检查这个计算出的容量是否足够,最后使用Arrays.copy() 拷贝一个新的数组。

javaguide-扩容机制分析

扩容方法

/**
      * Increases the capacity to ensure that it can hold at least the
      * number of elements specified by the minimum capacity argument.
      *
      * @param minCapacity the desired minimum capacity 最小容量
      *  扩容操作
      */
     private void grow(int minCapacity) {
         // overflow-conscious code
         // 扩容之前的数组容量
         int oldCapacity = elementData.length;
         // 计算扩容之后的容量,右移1位就是 除以2, 说明每次扩容增加 扩容前容量的一半
         int newCapacity = oldCapacity + (oldCapacity >> 1);
         // 如果增加一半的容量 小于 满足添加操作的最小容量,那么扩容容量 = 最小容量
         if (newCapacity - minCapacity < 0)
             newCapacity = minCapacity;
         //再检查新容量是否超出了ArrayList所定义的最大容量,
         //若超出了,则调用hugeCapacity()来比较minCapacity和 MAX_ARRAY_SIZE,
         //如果minCapacity大于MAX_ARRAY_SIZE,则新容量则为Interger.MAX_VALUE,否则,新容量大小则为 MAX_ARRAY_SIZE。
         if (newCapacity - MAX_ARRAY_SIZE > 0)
             newCapacity = hugeCapacity(minCapacity);
         // minCapacity is usually close to size, so this is a win:
         // 拷贝一个新的数组
         elementData = Arrays.copyOf(elementData, newCapacity);
     }
 
     /**
      *  计算 容量的最大值
      * @param minCapacity
      * @return
      */
     private static int hugeCapacity(int minCapacity) {
         // 这里就保证了最大容量 < Integer.MAX_VALUE,因为Integer.MAX_VALUE+ 1 < 0;
         if (minCapacity < 0) // overflow
             throw new OutOfMemoryError();
         return (minCapacity > MAX_ARRAY_SIZE) ?
             Integer.MAX_VALUE :
             MAX_ARRAY_SIZE;
     }

2.1.6 remove方法

remove 有两个方法

  1. remove(int i) 根据索引删除。检查索引,计算该索引之后右多少个元素,然后从该索引后一位向前拷贝一位,最后释放引用。
  2. remove(Object o) 根据数组中的元素删除,有多个相同的元素,只会删除索引小的那一个。先查询删除元素所在的索引,然后计算该索引之后右多少个元素,然后从该索引后一位向前拷贝一位,最后释放引用。
/**
      * Removes the element at the specified position in this list.
      * Shifts any subsequent elements to the left (subtracts one from their
      * indices).
      *
      * @param index the index of the element to be removed
      * @return the element that was removed from the list
      * @throws IndexOutOfBoundsException {@inheritDoc}
      * 这个remove是根据索引来删除元素
      */
 public E remove(int index) {
     rangeCheck(index); // 检查索引 index < size
 
     modCount++; // 修改次数 + 1
     // 获取要删除的元素
     E oldValue = elementData(index); // 这里如果index < 0 会报数组越界异常
     // 计算 要删除元素后面有多少个元素
     int numMoved = size - index - 1;
     if (numMoved > 0)
         // 将 删除元素后面的元素拷贝到前一位
         System.arraycopy(elementData, index+1, elementData, index,
                          numMoved);
     // 去掉最后一位的引用,便于JVM GC的时候就会回收
     elementData[--size] = null; // clear to let GC do its work
     // 返回删除元素的值
     return oldValue;
 }
 
 /**
      * Removes the first occurrence of the specified element from this list,
      * if it is present.  If the list does not contain the element, it is
      * unchanged.  More formally, removes the element with the lowest index
      * <tt>i</tt> such that
      * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>
      * (if such an element exists).  Returns <tt>true</tt> if this list
      * contained the specified element (or equivalently, if this list
      * changed as a result of the call).
      *
      * @param o element to be removed from this list, if present
      * @return <tt>true</tt> if this list contained the specified element
      * 这个remove 是根据集合中的元素来删除
      */
 public boolean remove(Object o) {
     // 遍历集合找到要删除的值的索引,然后调用fastRemove(),只会删除遇到的第一个相同的元素
     if (o == null) {
         for (int index = 0; index < size; index++)
             if (elementData[index] == null) {
                 fastRemove(index);
                 return true;
             }
     } else {
         for (int index = 0; index < size; index++)
             if (o.equals(elementData[index])) {
                 fastRemove(index);
                 return true;
             }
     }
     return false;
 }
 
 /*
      * Private remove method that skips bounds checking and does not
      * return the value removed.
      */
 private void fastRemove(int index) {
     modCount++;
     // 计算删除元素后面有多少个元素
     int numMoved = size - index - 1;
     if (numMoved > 0)
         // 拷贝到前一位
         System.arraycopy(elementData, index+1, elementData, index,
                          numMoved);
     elementData[--size] = null; // clear to let GC do its work
 }

2.1.7 System.arraycopy()和 Arrays.copyOf()方法

// 我们发现 arraycopy 是一个 native 方法,接下来我们解释一下各个参数的具体意义
 /**
     *   复制数组
     * @param src 源数组
     * @param srcPos 源数组中的起始位置
     * @param dest 目标数组
     * @param destPos 目标数组中的起始位置
     * @param length 要复制的数组元素的数量
     */
 public static native void arraycopy(Object src,  int  srcPos,
                                     Object dest, int destPos,
                                     int length);
 
 public static int[] copyOf(int[] original, int newLength) {
     // 申请一个新的数组
     int[] copy = new int[newLength];
     // 调用System.arraycopy,将源数组中的数据进行拷贝,并返回新的数组
     System.arraycopy(original, 0, copy, 0,
                      Math.min(original.length, newLength));
     return copy;
 }

arraycopy() 需要目标数组,将原数组拷贝到你自己定义的数组里或者原数组,而且可以选择拷贝的起点和长度以及放入新数组中的位置 copyOf() 是系统自动在内部新建一个数组,并返回该数组。

2.1.8 ensureCapacity方法

/**
     如有必要,增加此 ArrayList 实例的容量,以确保它至少可以容纳由minimum capacity参数指定的元素数。
      *
      * @param   minCapacity   所需的最小容量
      */
     public void ensureCapacity(int minCapacity) {
         int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
             // any size if not default element table
             ? 0
             // larger than default for default empty table. It's already
             // supposed to be at default size.
             : DEFAULT_CAPACITY;
 
         if (minCapacity > minExpand) {
             ensureExplicitCapacity(minCapacity);
         }
     }

最好在 add 大量元素之前用 ensureCapacity 方法,以减少增量重新分配的次数

2.2 Vector

Vector 和 ArrayList 的一些方法的实现 基本相同,Vector对外提供访问的方法 除了构造方法都 使用了 synchronized 修饰。

通过下面的源码发现,每个方法中都添加了synchronized的关键字来保证同步,所以它是线程安全的,但正是这些方法的同步,让它的效率大大的降低了,比ArrayList的效率要慢。

2.2.1 类的静态字段和普通字段

/**
     * The array buffer into which the components of the vector are
     * stored. The capacity of the vector is the length of this array buffer,
     * and is at least large enough to contain all the vector's elements.
     *
     * <p>Any array elements following the last element in the Vector are null.
     *
     * @serial
     * 和ArrayList相同,使用Object[] 保存数据
     */
protected Object[] elementData;

/**
     * The number of valid components in this {@code Vector} object.
     * Components {@code elementData[0]} through
     * {@code elementData[elementCount-1]} are the actual items.
     *
     * @serial
     * 数组中 元素的数量 和ArrayList 的size相同。
     */
protected int elementCount;

/**
     * The amount by which the capacity of the vector is automatically
     * incremented when its size becomes greater than its capacity.  If
     * the capacity increment is less than or equal to zero, the capacity
     * of the vector is doubled each time it needs to grow.
     * 这个值如果大于0,那么在扩容的时候扩容之后的数组长度就等于扩容之前的数组长度 + 这个值
     * 如果 小于等于0,那么在扩容的时候扩容之后的数组长度就等于扩容之前的数组长度 + 扩容之前的数组长度
     * @serial
     */
protected int capacityIncrement;

/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -2767605614048989439L;
/**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     * 要分配数组的最大大小
     */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

2.2.2 构造方法

Vector和ArrayList不同,Vector创建数组在构造方法中就进行了,如果没有指定那么数组长度就是10

/**
     * Constructs an empty vector with the specified initial capacity and
     * capacity increment.
     *
     * @param   initialCapacity     the initial capacity of the vector
     * @param   capacityIncrement   the amount by which the capacity is
     *                              increased when the vector overflows
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
public Vector(int initialCapacity, int capacityIncrement) {
    super();
    // 不能小于0
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    // 定义初始容量,然后创建一个数组
    this.elementData = new Object[initialCapacity];
    // capacityIncrement 每次扩容的时候增加的值
    this.capacityIncrement = capacityIncrement;
}

/**
     * Constructs an empty vector with the specified initial capacity and
     * with its capacity increment equal to zero.
     *
     * @param   initialCapacity   the initial capacity of the vector
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
public Vector(int initialCapacity) {
    this(initialCapacity, 0);
}

/**
     * Constructs an empty vector so that its internal data array
     * has size {@code 10} and its standard capacity increment is
     * zero.
     * 默认构造方法,那么初始容量就等于10
     */
public Vector() {
    this(10);
}

/**
     * Constructs a vector containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this
     *       vector
     * @throws NullPointerException if the specified collection is null
     * @since   1.2
     */
public Vector(Collection<? extends E> c) {
    elementData = c.toArray();
    elementCount = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}

2.2.3 add方法

synchronized修饰,锁当前对象

添加元素:

  1. add(E e); 添加元素到数组中元素的末尾,首先检查是否需要扩容,添加。
  2. add(int i, E e); 添加元素到指定索引位置,检查i的合法性 i <= elementCount,说明只能添加到已有元素的位置(包括末尾),检查是否需要扩容,拷贝,从i位置开始向后拷贝一位,添加到指定位置。
/**
     * Appends the specified element to the end of this Vector.
     *
     * @param e element to be appended to this Vector
     * @return {@code true} (as specified by {@link Collection#add})
     * @since 1.2
     */
public synchronized boolean add(E e) {
    modCount++; // 结构改变了就+1
    // 判断是否需要扩容
    ensureCapacityHelper(elementCount + 1);
    // 添加到数组元素的末尾
    elementData[elementCount++] = e;
    return true;
}

/**
     * This implements the unsynchronized semantics of ensureCapacity.
     * Synchronized methods in this class can internally call this
     * method for ensuring capacity without incurring the cost of an
     * extra synchronization.
     *
     * @see #ensureCapacity(int)
     * 判断是否需要扩容
     */
private void ensureCapacityHelper(int minCapacity) {
    // overflow-conscious code
    //minCapacity: 满足添加操作,最小的容量
    if (minCapacity - elementData.length > 0)
        //扩容
        grow(minCapacity);
}


/**
     * Inserts the specified element at the specified position in this Vector.
     * Shifts the element currently at that position (if any) and any
     * subsequent elements to the right (adds one to their indices).
     *
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws ArrayIndexOutOfBoundsException if the index is out of range
     *         ({@code index < 0 || index > size()})
     * @since 1.2
     * 向指定索引位置上添加元素
     */
public void add(int index, E element) {
    insertElementAt(element, index);
}

/**
     * Inserts the specified object as a component in this vector at the
     * specified {@code index}. Each component in this vector with
     * an index greater or equal to the specified {@code index} is
     * shifted upward to have an index one greater than the value it had
     * previously.
     *
     * <p>The index must be a value greater than or equal to {@code 0}
     * and less than or equal to the current size of the vector. (If the
     * index is equal to the current size of the vector, the new element
     * is appended to the Vector.)
     *
     * <p>This method is identical in functionality to the
     * {@link #add(int, Object) add(int, E)}
     * method (which is part of the {@link List} interface).  Note that the
     * {@code add} method reverses the order of the parameters, to more closely
     * match array usage.
     *
     * @param      obj     the component to insert
     * @param      index   where to insert the new component
     * @throws ArrayIndexOutOfBoundsException if the index is out of range
     *         ({@code index < 0 || index > size()})
     */
public synchronized void insertElementAt(E obj, int index) {
    modCount++;// 结构改变 +1
    // 判断index index <= elementCount
    if (index > elementCount) {
        throw new ArrayIndexOutOfBoundsException(index
                                                 + " > " + elementCount);
    }
    // 判断是否需要扩容
    ensureCapacityHelper(elementCount + 1);
    // 和ArrayList使用的方法相同,从索引index开始向后拷贝一位
    System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
    // 添加元素
    elementData[index] = obj;
    elementCount++;
}

2.2.4 grow方法

和ArrayList的扩容不同之处在于:扩容后数组长度的计算。

ArrayList的扩容后数组长度等于旧数组长度 + 旧数组长度 >> 1

Vector的扩容数组长度等于旧数组长度+自定义的增加的值(如果该值<= 0), 那么就是旧数组长度+旧数组长度

/**
     * 扩容方法
     * @param minCapacity 要满足的最小容量
     */
private void grow(int minCapacity) {
    // overflow-conscious code
    // 扩容前的数组长度
    int oldCapacity = elementData.length;
    // 扩容之后的长度 = 扩容前数组长度 + (capacityIncrement 或 扩容前数组)
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                     capacityIncrement : oldCapacity);
    // 不能满足最小的容量,那么扩容后的数组长度 = 满足的最小容量
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // 扩容之后的数组长度 大于 最大的容量
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        // 新数组容量 = 如果要满足的最小容量大于数组最大容量,那么就等于Integer的最大值,否则等于数组最大容量
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}

/**
     * @param minCapacity 要满足的最小容量
     * @return 如果要满足的最小容量大于数组最大容量,那么就等于Integer的最大值,否则等于数组最大容量
     */
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
    MAX_ARRAY_SIZE;
}

2.2.5 remove 方法

和ArrayList方法一样的实现,不同的是 使用了 synchronized 关键字修饰了。

/**
     * Removes the element at the specified position in this Vector.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).  Returns the element that was removed from the Vector.
     *
     * @throws ArrayIndexOutOfBoundsException if the index is out of range
     *         ({@code index < 0 || index >= size()})
     * @param index the index of the element to be removed
     * @return element that was removed
     * @since 1.2
     */
public synchronized E remove(int index) {
    modCount++;
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);
    E oldValue = elementData(index);

    int numMoved = elementCount - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--elementCount] = null; // Let gc do its work

    return oldValue;
}

2.3 LinkedList

类的字段
// 版本序列号
 private static final long serialVersionUID = 876323262645176354L;
 /**
      * 链表中节点的数量
      */
 transient int size = 0;
 
 /**
      * Pointer to first node.
      * Invariant不变量: (first == null && last == null) ||
      *            (first.prev == null && first.item != null)
      *
      * 链表头节点
      */
 transient Node<E> first;
 
 /**
      * Pointer to last node.
      * Invariant 不变量: (first == null && last == null) ||
      *            (last.next == null && last.item != null)
      * 链表尾节点           
      */
 transient Node<E> last;
Node节点
/**
     * 链表中的节点
     * @param <E>
     */
private static class Node<E> {
    E item;
    Node<E> next;
    Node<E> prev;

    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}
构造方法
public LinkedList() {
 }
 
 /**
      * Constructs a list containing the elements of the specified
      * collection, in the order they are returned by the collection's
      * iterator.
      *
      * @param  c the collection whose elements are to be placed into this list
      * @throws NullPointerException if the specified collection is null
      */
 public LinkedList(Collection<? extends E> c) {
     this();
     addAll(c);
 }
add方法
/**
     * Appends the specified element to the end of this list.
     *
     * <p>This method is equivalent to {@link #addLast}.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
public boolean add(E e) {
    linkLast(e);
    return true;
}

/**
     * Appends the specified element to the end of this list.
     *
     * <p>This method is equivalent to {@link #add}.
     *
     * @param e the element to add
     */
public void addLast(E e) {
    linkLast(e);
}

/**
     * Links e as last element.
     * 添加元素到链表末尾
     */
void linkLast(E e) {
    //l:最后一个节点
    final Node<E> l = last;
    //创建一个新的节点
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    // l == null 说明 链表中还没有节点,添加第一个节点
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    // 节点数量+1
    size++;
    modCount++;
}

/**
     * Inserts the specified element at the beginning of this list.
     *
     * @param e the element to add
     */
public void addFirst(E e) {
    linkFirst(e);
}

/**
     * Links e as first element.
     * // 添加节点到链表头部
     */
private void linkFirst(E e) {
    final Node<E> f = first;
    final Node<E> newNode = new Node<>(null, e, f);
    first = newNode;
    if (f == null)
        last = newNode;
    else
        f.prev = newNode;
    size++;
    modCount++;
}


/**
     * Inserts all of the elements in the specified collection into this
     * list, starting at the specified position.  Shifts the element
     * currently at that position (if any) and any subsequent elements to
     * the right (increases their indices).  The new elements will appear
     * in the list in the order that they are returned by the
     * specified collection's iterator.
     *
     * @param index index at which to insert the first element
     *              from the specified collection
     * @param c collection containing elements to be added to this list
     * @return {@code true} if this list changed as a result of the call
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @throws NullPointerException if the specified collection is null
     */
public boolean addAll(int index, Collection<? extends E> c) {
    //检查index, 0<=index<=size
    checkPositionIndex(index);

    Object[] a = c.toArray();
    int numNew = a.length;
    if (numNew == 0)
        return false;

    // pred:要插入节点的前一个节点
    // succ: index索引位置的节点
    Node<E> pred, succ;
    // index == size 说明 向链表尾部添加节点
    if (index == size) {
        succ = null;
        pred = last;
    } else { //说明index < size 向指定索引位置添加节点
        succ = node(index);
        pred = succ.prev;
    }
    // 遍历数组
    for (Object o : a) {
        @SuppressWarnings("unchecked") E e = (E) o;
        Node<E> newNode = new Node<>(pred, e, null);
        // 说明第一次添加
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        // 新添加的节点变成前一个节点
        pred = newNode;
    }
    // 说明 数组是向链表尾部添加的节点,last = 最后添加的节点即可
    if (succ == null) {
        last = pred;
    } else {// 说明 数组向链表指定位置添加的节点,那么需要将index位置以及后面的节点重新放入链表中
        pred.next = succ;
        succ.prev = pred;
    }
    // 节点增加
    size += numNew;
    modCount++;
    return true;
}
get方法
/**
      * Returns the element at the specified position in this list.
      *
      * @param index index of the element to return
      * @return the element at the specified position in this list
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
 public E get(int index) {
     // 检查索引 0 <= index < size
     checkElementIndex(index);
     return node(index).item;
 }
 
 /**
      * Returns the (non-null) Node at the specified element index.
      * 
      * 返回索引处的节点
      */
 Node<E> node(int index) {
     // assert isElementIndex(index);
     // index 小于 size / 2 说明 索引处节点在链表的左半部分,那么从头遍历
     if (index < (size >> 1)) {
         Node<E> x = first;
         for (int i = 0; i < index; i++)
             x = x.next;
         return x;
     } else {// 索引节点在链表右半部分,从尾遍历
         Node<E> x = last;
         for (int i = size - 1; i > index; i--)
             x = x.prev;
         return x;
     }
 }
remove方法
/**
      * Removes the first occurrence of the specified element from this list,
      * if it is present.  If this list does not contain the element, it is
      * unchanged.  More formally, removes the element with the lowest index
      * {@code i} such that
      * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>
      * (if such an element exists).  Returns {@code true} if this list
      * contained the specified element (or equivalently, if this list
      * changed as a result of the call).
      *
      * @param o element to be removed from this list, if present
      * @return {@code true} if this list contained the specified element
      */
 public boolean remove(Object o) {
     if (o == null) {
         for (Node<E> x = first; x != null; x = x.next) {
             if (x.item == null) {
                 unlink(x);
                 return true;
             }
         }
     } else {
         for (Node<E> x = first; x != null; x = x.next) {
             if (o.equals(x.item)) {
                 unlink(x);
                 return true;
             }
         }
     }
     return false;
 }
 
 /**
      * Removes the element at the specified position in this list.  Shifts any
      * subsequent elements to the left (subtracts one from their indices).
      * Returns the element that was removed from the list.
      *
      * @param index the index of the element to be removed
      * @return the element previously at the specified position
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
 public E remove(int index) {
     // 检查索引 0 <= index < size
     checkElementIndex(index);
     return unlink(node(index));
 }
 
 /**
      * Unlinks non-null node x.
      * 删除x节点
      */
 E unlink(Node<E> x) {
     // assert x != null;
     final E element = x.item;
     final Node<E> next = x.next;
     final Node<E> prev = x.prev;
 
     if (prev == null) {
         first = next;
     } else {
         prev.next = next;
         x.prev = null; // 取消引用,方便JVM GC
     }
 
     if (next == null) {
         last = prev;
     } else {
         next.prev = prev;
         x.next = null; // 取消引用,方便JVM GC
     }
 
     x.item = null;
     size--;
     modCount++;
     return element;
 }

3 Set

3.1 HashSet源码

HashSet就是对HashMap的一些封装。

类的常量和字段

从字段中就可以看出hashSet 就是基于HashMap扩展的,内部使用的就是map,value值使用一个空对象代替

//版本序列号
 static final long serialVersionUID = -5024744406713321676L;
 
 // HashSet 就是基于map 扩展的 使用map的key,value用一个空对象代替
 private transient HashMap<E,Object> map;
 
 // Dummy value to associate with an Object in the backing Map
 // 作为Map的value值
 private static final Object PRESENT = new Object();

构造方法

有5个构造方法,都是创建一个HashMap,也说明了hashSet 就是 使用的hashMap。

/**
      * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
      * default initial capacity (16) and load factor (0.75).
      */
 public HashSet() {
     map = new HashMap<>();
 }
 
 /**
      * Constructs a new set containing the elements in the specified
      * collection.  The <tt>HashMap</tt> is created with default load factor
      * (0.75) and an initial capacity sufficient to contain the elements in
      * the specified collection.
      *
      * @param c the collection whose elements are to be placed into this set
      * @throws NullPointerException if the specified collection is null
      */
 public HashSet(Collection<? extends E> c) {
     map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
     addAll(c);
 }
 
 /**
      * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
      * the specified initial capacity and the specified load factor.
      *
      * @param      initialCapacity   the initial capacity of the hash map
      * @param      loadFactor        the load factor of the hash map
      * @throws     IllegalArgumentException if the initial capacity is less
      *             than zero, or if the load factor is nonpositive
      */
 public HashSet(int initialCapacity, float loadFactor) {
     map = new HashMap<>(initialCapacity, loadFactor);
 }
 
 /**
      * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
      * the specified initial capacity and default load factor (0.75).
      *
      * @param      initialCapacity   the initial capacity of the hash table
      * @throws     IllegalArgumentException if the initial capacity is less
      *             than zero
      */
 public HashSet(int initialCapacity) {
     map = new HashMap<>(initialCapacity);
 }
 
 /**
      * Constructs a new, empty linked hash set.  (This package private
      * constructor is only used by LinkedHashSet.) The backing
      * HashMap instance is a LinkedHashMap with the specified initial
      * capacity and the specified load factor.
      *
      * @param      initialCapacity   the initial capacity of the hash map
      * @param      loadFactor        the load factor of the hash map
      * @param      dummy             ignored (distinguishes this
      *             constructor from other int, float constructor.)
      * @throws     IllegalArgumentException if the initial capacity is less
      *             than zero, or if the load factor is nonpositive
      */
 HashSet(int initialCapacity, float loadFactor, boolean dummy) {
     map = new LinkedHashMap<>(initialCapacity, loadFactor);
 }

看一下HashSet内部的方法

image.png

一些 size()isEmpty()contains()add()remove()等方法都是直接调用的hashMap的方法。没有什么可看的。

3.2 LinkedHashSet源码

public class LinkedHashSet<E>
    extends HashSet<E>
    implements Set<E>, Cloneable, java.io.Serializable {

可以看到LinkedHashSet 继承了HashSet,那么就可以使用HashSet的一些公有方法。

LinkedHashSet中只有4个构造方法,没有其它留个外部的方法.

public class LinkedHashSet<E>
     extends HashSet<E>
     implements Set<E>, Cloneable, java.io.Serializable {
 
     private static final long serialVersionUID = -2851667679971038690L;
 
     /**
      * Constructs a new, empty linked hash set with the specified initial
      * capacity and load factor.
      *
      * @param      initialCapacity the initial capacity of the linked hash set
      * @param      loadFactor      the load factor of the linked hash set
      * @throws     IllegalArgumentException  if the initial capacity is less
      *               than zero, or if the load factor is nonpositive
      */
     public LinkedHashSet(int initialCapacity, float loadFactor) {
         super(initialCapacity, loadFactor, true);
     }
 
     /**
      * Constructs a new, empty linked hash set with the specified initial
      * capacity and the default load factor (0.75).
      *
      * @param   initialCapacity   the initial capacity of the LinkedHashSet
      * @throws  IllegalArgumentException if the initial capacity is less
      *              than zero
      */
     public LinkedHashSet(int initialCapacity) {
         super(initialCapacity, .75f, true);
     }
 
     /**
      * Constructs a new, empty linked hash set with the default initial
      * capacity (16) and load factor (0.75).
      */
     public LinkedHashSet() {
         super(16, .75f, true);
     }
 
     /**
      * Constructs a new linked hash set with the same elements as the
      * specified collection.  The linked hash set is created with an initial
      * capacity sufficient to hold the elements in the specified collection
      * and the default load factor (0.75).
      *
      * @param c  the collection whose elements are to be placed into
      *           this set
      * @throws NullPointerException if the specified collection is null
      */
     public LinkedHashSet(Collection<? extends E> c) {
         super(Math.max(2*c.size(), 11), .75f, true);
         addAll(c);
     }
 
     /**
      * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
      * and <em>fail-fast</em> {@code Spliterator} over the elements in this set.
      *
      * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
      * {@link Spliterator#DISTINCT}, and {@code ORDERED}.  Implementations
      * should document the reporting of additional characteristic values.
      *
      * @implNote
      * The implementation creates a
      * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
      * from the set's {@code Iterator}.  The spliterator inherits the
      * <em>fail-fast</em> properties of the set's iterator.
      * The created {@code Spliterator} additionally reports
      * {@link Spliterator#SUBSIZED}.
      *
      * @return a {@code Spliterator} over the elements in this set
      * @since 1.8
      */
     @Override
     public Spliterator<E> spliterator() {
         return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);
     }
 }

注意:构造方法中调用的父类的构造方法都是同一个(下面的),创建的是一个LInkedHashMap,所以可以实现有序性。

HashSet(int initialCapacity, float loadFactor, boolean dummy) {
     map = new LinkedHashMap<>(initialCapacity, loadFactor);
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值