ArrayList, LinkedList and Vector source code analysis

ArrayList, LinkedList and Vector source code analysis

ArrayList

ArrayList is an underlying class that uses arrays to store objects, but is not a thread-safe collection class

ArrayList class structure relationship

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
        {
        
        }

ArrayList implements the List interface, which defines some methods for adding and deleting lists through subscripts.

ArrayList implements the RandomAccess interface. This interface is a mark interface. There is no method in the interface. The bottom layer of ArrayList uses arrays to store objects. Of course, it can be randomly accessed through subscripts. The speed will be fast but the addition and deletion of elements will be slow, and LinkedList is implemented through a linked list. It does not implement the RandomAccess interface, which is slow during query but increases the speed of deletion.

So when using a collection to traverse a large amount of data, you can first use instanceof to determine whether the collection implements RandomAccess

public void test1() {
		List<Integer> list=new ArrayList<Integer>();
		list.add(1);
		if(list instanceof RandomAccess) {//RandomAccess实现类,使用下标访问
			for(int i=0;i<list.size();i++) {
				//todo
			}
		}else {//不是RandomAccess实现类,使用iterator遍历
			Iterator<Integer> iterator = list.iterator();
			while(iterator.hasNext()) {
				//todo
			}
		}
	}

ArrayList implements the Cloneable interface, it can legally call clone method, if not implement the Cloneable interface, then throws CloneNotSupporteddException , see

ArrayList implements the Serializable interface, which can serialize objects for transmission or persistence, see details

Attributes

//序列化Id
private static final long serialVersionUID = 8683452581122892189L;

//默认初始化大小
private static final int DEFAULT_CAPACITY = 10;

//空数组对象,用于有参构造且初始化大小为0时
private static final Object[] EMPTY_ELEMENTDATA = {};

//空数组对象,用于无参构造时,这两个属性主要用来区分创建ArrayList时有没有指定容量
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

//保存对象的容器,使用transient修饰即在序列化时,不进行序列化,这是因为ArrayList添加了序列化方法private void writeObject(java.io.ObjectOutputStream s)只把保存的数据序列化了,而不是把整个数组序列化,提高效率
transient Object[] elementData;

//保存的对象个数
private int size;

//最大容量2的31次方减9
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

Constructor

ArrayList provides three constructors, one is a constructor that specifies the initialization size, one is a constructor with no parameter default initialization size, and one is a constructor that uses a collection initialization

public ArrayList(int initialCapacity) {
  if (initialCapacity > 0) {
    //数组的大小为指定大小
    this.elementData = new Object[initialCapacity];
  } else if (initialCapacity == 0) {
    //大小为0用一个共享的空数组赋值
    this.elementData = EMPTY_ELEMENTDATA;
  } else {
    throw new IllegalArgumentException("Illegal Capacity: "+
                                       initialCapacity);
  }
}

public ArrayList() {
  //用共享的空数组赋值,不使用EMPTY_ELEMENTDATA主要是区分是使用的哪个构造器
  this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

public ArrayList(Collection<? extends E> c) {
  elementData = c.toArray();
  if ((size = elementData.length) != 0) {
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
      elementData = Arrays.copyOf(elementData, size, Object[].class);
  } else {
    // 集合为空,使用空数组
    this.elementData = EMPTY_ELEMENTDATA;
  }
}

Add element

Add elements at the end of the array

public boolean add(E e) {
  ensureCapacityInternal(size + 1);  // Increments modCount!!
  elementData[size++] = e;
  return true;
}

private void ensureCapacityInternal(int minCapacity) {
  ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//计算容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
  if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//通过无参构造器创建
    return Math.max(DEFAULT_CAPACITY, minCapacity);
  }
  return minCapacity;
}

private void ensureExplicitCapacity(int minCapacity) {
  modCount++;

  // 如果最小需要的容量>数组大小
  if (minCapacity - elementData.length > 0)
    //进行扩容
    grow(minCapacity);
}

private void grow(int minCapacity) {
  
  int oldCapacity = elementData.length;
  //新容量=老容量+老容量>>1;老容量>>1即老容量无符号右移1位,即除以2,所以最后新容量是老容量的1.5倍
  int newCapacity = oldCapacity + (oldCapacity >> 1);
  if (newCapacity - minCapacity < 0)//新容量比最小容量小那么把最小容量赋值给新容量
    newCapacity = minCapacity;
  if (newCapacity - MAX_ARRAY_SIZE > 0)//如果minCapacity很大,计算得出newCapacity超出最大容量
    newCapacity = hugeCapacity(minCapacity);
  // 复制未扩容之前的数据
  elementData = Arrays.copyOf(elementData, newCapacity);
}

private static int hugeCapacity(int minCapacity) {
  if (minCapacity < 0) // overflow
    throw new OutOfMemoryError();
  //如果最小容量还超出ArrayList规定的最大值那么数组大小为Integer.MAX_VALUE否则为ArrayList规定的最大值
  return (minCapacity > MAX_ARRAY_SIZE) ?
    Integer.MAX_VALUE :
  MAX_ARRAY_SIZE;
}

Add element at specified position

public void add(int index, E element) {
  //检查添加元素的下标
  rangeCheckForAdd(index);
	//检查容量,进行扩容
  ensureCapacityInternal(size + 1);  // Increments modCount!!
  
  // public static native void arraycopy(src, srcPos,dest, destPos,length);
  //src:源数组;srcPos:源数组起始下标;dest:目标数组;destPos:目标数组起始下标;length:拷贝长度
  System.arraycopy(elementData, index, elementData, index + 1,
                   size - index);
  elementData[index] = element;
  size++;
}

private void rangeCheckForAdd(int index) {
  //元素的下标必须为0-size
  if (index > size || index < 0)
    throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

Remove element

Remove elements according to subscript

public E remove(int index) {
  //检查下标
  rangeCheck(index);

  modCount++;
  //按照下标获取元素
  E oldValue = elementData(index);
  //计算需要移动的数据个数
  int numMoved = size - index - 1;
  if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
                     numMoved);
  //清理数组elementData[size]位置的元素
  elementData[--size] = null; // clear to let GC do its work

  return oldValue;
}

private void rangeCheck(int index) {
  //下标必须在0到size-1之间
  if (index >= size)
    throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

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

Remove elements by value

public boolean remove(Object o) {
  if (o == null) {//如果移除的元素为null,依次遍历保存的元素,移除第一个为null的元素
    for (int index = 0; index < size; index++)
      if (elementData[index] == null) {
        //移除
        fastRemove(index);
        return true;
      }
  } else {
    for (int index = 0; index < size; index++)
      //使用equals判断是否相等
      if (o.equals(elementData[index])) {
        fastRemove(index);
        return true;
      }
  }
  return false;
}

private void fastRemove(int index) {
  modCount++;
  //计算移除后需要移动的元素个数
  int numMoved = size - index - 1;
  if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
                     numMoved);
  //清理数组elementData[size]位置的元素
  elementData[--size] = null; // clear to let GC do its work
}

modCount

ArrayList performs modCount + 1 operation during add, set, and remove. This property is related to fast fail. When the object creates an Iterator object, it will assign modCount to expectedModCount. When using Iterator to traverse, if the object's modCount is found Not equal to expectedModCount, will directly throw ConcurrentModificationException exception

public Iterator<E> iterator() {
        return new Itr();
    }

private class Itr implements Iterator<E> {
  int cursor;       // index of next element to return
  int lastRet = -1; // index of last element returned; -1 if no such
  int expectedModCount = modCount;
  ...
    public E next() {
    checkForComodification();
    ...
  }

  final void checkForComodification() {
    if (modCount != expectedModCount)//直接抛出异常
      throw new ConcurrentModificationException();
  }

Occurrence: When Iterator traverses, if the object's modCount and expectedModCount are not equal, an exception will be thrown, mainly in these situations

  • When using iterator to traverse, add, remove and other operations that destroy the structure
  • In a multi-threaded environment, when one thread is traversing, another thread performs operations such as add and remove to destroy the structure

Through source code learning, I found that the set method did not increase modCount, why? Is it possible that one thread is using iterator to traverse, and another thread changes the element of a position, Iterator does not need to throw an exception? If you know, please enlighten me!

LinkedList

LinkedList class structure

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

LinkedList inherits AbstractSequentialList to achieve random access through Iterator

LinkedList implements the List interface to perform operations such as addition and deletion

LinkedList implements DeQue, allowing enqueue and dequeue at both ends of the queue, so you can use LinkedList as a queue or stack

LinkedList implements Cloneable, which can quickly clone objects through clone

LinkedList implements the Serializable interface, which can serialize LinkedList for streaming operations

Constructor

public LinkedList() {
    }

//使用集合初始化链表
public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

Attributes

//链表的大小,transient表明在序列化的时候不进行序列化,但是LinkedList自定义的序列化方法中进行了序列化
transient int size = 0;

//链表的头节点
transient Node<E> first;

//链表的尾节点
transient Node<E> last;

node

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;
  }
}

You can see that LinkedList is a doubly linked list

method

Deque is a double-ended linked list, that is, the linked list can be used as a stack and queue

The getFirst method is equivalent to the element method in Queue. If the queue is empty, an exception is thrown

public E getFirst() {
  final Node<E> f = first;
  if (f == null)
    throw new NoSuchElementException();
  return f.item;
}

getLast method

public E getLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return l.item;
    }

The removeFirst method is equivalent to the Queue's remove method. It deletes the head element. If the queue is empty, an exception is thrown.

public E removeFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return unlinkFirst(f);
    }

private E unlinkFirst(Node<E> f) {
  // assert f == first && f != null;
  final E element = f.item;
  final Node<E> next = f.next;
  f.item = null;
  f.next = null; // help GC
  first = next;
  if (next == null)
    //如果原头节点的后继为空,那么把尾指针也更新为空
    last = null;
  else
    //原头节点的后继为不空,那么需要把它的前驱更新为空
    next.prev = null;
  //更新链表大小
  size--;
  modCount++;
  return element;
}

removeLast method, if the team is empty, throw an exception

public E removeLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return unlinkLast(l);
    }

private E unlinkLast(Node<E> l) {
        // assert l == last && l != null;
        final E element = l.item;
        final Node<E> prev = l.prev;
        l.item = null;
        l.prev = null; // help GC
        last = prev;
        if (prev == null)
          //如果原尾指针的前驱为空,那么头指针指向也为空
            first = null;
        else
          //原尾指针的前驱不为空,那么它的后继应该改为空
            prev.next = null;
        size--;
        modCount++;
        return element;
    }

The addFirst method is equivalent to the push method in Statck

public void addFirst(E e) {
  linkFirst(e);
}

private void linkFirst(E e) {
  final Node<E> f = first;
  //创建一个前驱为空,后驱为first的新节点
  final Node<E> newNode = new Node<>(null, e, f);
  first = newNode;
  if (f == null)
    //如果原头指针为空,那么把尾指针也赋值为新加节点
    last = newNode;
  else
    //原头指正不空,把它的前驱更新为新节点
    f.prev = newNode;
  size++;
  modCount++;
}

addLast method, equivalent to the add method in Queue

public void addLast(E e) {
        linkLast(e);
    }

void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
          //如果原为指针指向就为空,那么头指针也指向新节点
            first = newNode;
        else
          //原为指针指向就不为空,那么它的后继更新为新加节点
            l.next = newNode;
        size++;
        modCount++;
    }

The add method is to rewrite the method in AbstractList, that is, add elements to the List

public boolean add(E e) {
        linkLast(e);
        return true;
 }
void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

The remove method removes the specified element from the linked list

public boolean remove(Object o) {
        if (o == null) {
          //如果要移除的对象为null,那么取链表中找第一个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)) {//使用equals比较两个对象是否相同
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

The addAll method adds the elements of the specified collection to the linked list

public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }

 public boolean addAll(int index, Collection<? extends E> c) {
        checkPositionIndex(index);

        Object[] a = c.toArray();
        int numNew = a.length;
   //如果集合大小为0
        if (numNew == 0)
            return false;
//什么一个前驱节点和一个后继节点
        Node<E> pred, succ;
        if (index == size) {
          //如果添加的位置恰好是size即在链表最后添加,那么后继为null,前驱为链表尾指针
            succ = null;
            pred = last;
        } else {
            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;
        }

        if (succ == null) {//如果没有后继节点
          //把尾指针指向'前驱节点'
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        }

        size += numNew;
        modCount++;
        return true;
    }

The clear method clears the linked list, but modCount will not clear it

public void clear() {
        for (Node<E> x = first; x != null; ) {
            Node<E> next = x.next;
          //help GC?
            x.item = null;
            x.next = null;
            x.prev = null;
            x = next;
        }
        first = last = null;
        size = 0;
        modCount++;
    }

get method to get the specified subscript element, illegal subscript throws an exception

public E get(int index) {
  checkElementIndex(index);
  return node(index).item;
}
Node<E> node(int index) {
  // assert isElementIndex(index);
  //通过一个二分遍历拿元素
  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;
  }
}

The set method sets the value of the specified subscript element. The illegal subscript throws an exception. Is the set method modCount not ++? why?

public E set(int index, E element) {
  checkElementIndex(index);
  //获取元素
  Node<E> x = node(index);
  E oldVal = x.item;
  //替换
  x.item = element;
  return oldVal;
}

add method, specify the subscript to add elements, illegal subscript throws an exception

public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)//链表尾添加元素
            linkLast(element);
        else
          //链表中间位置添加元素
            linkBefore(element, node(index));
    }
void linkBefore(E e, Node<E> succ) {
        // assert succ != null;
        final Node<E> pred = succ.prev;
        final Node<E> newNode = new Node<>(pred, e, succ);
        succ.prev = newNode;
        if (pred == null)//添加元素位置前驱为null,即添加位置本来就是头指针位置
            first = newNode;
        else
          //更新前驱的next为当前添加节点
            pred.next = newNode;
        size++;
        modCount++;
    }

remove method, remove the specified subscript element, illegal subscript throws an exception

public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }

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) {//如果移除节点的前驱为null,即移除节点为头指针指向位置
            first = next;
        } else {
            prev.next = next;
          //help GC?
            x.prev = null;
        }

        if (next == null) {//如果移除节点的后继节点为null,即移除节点是尾指针指向位置
            last = prev;
        } else {
            next.prev = prev;
          //help GC?
            x.next = null;
        }
		//help GC?
        x.item = null;
        size--;
        modCount++;
        return element;
    }

The peek method to obtain the head node of the linked list can be the Queue / Stack method, the Queue method obtains the team player element, and the Stack method obtains the top element of the stack

public E peek() {
  final Node<E> f = first;
  return (f == null) ? null : f.item;
}

element method, to get the head node of the linked list, different from the peek method, if the queue is empty, an exception is thrown

public E element() {
  return getFirst();
}

public E getFirst() {
  final Node<E> f = first;
  if (f == null)
    //链表空抛出异常
    throw new NoSuchElementException();
  return f.item;
}

The poll method removes the head node of the linked list. If the linked list is empty, null is returned.

public E poll() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }

The remove method removes the head node of the linked list

public E remove() {
  return removeFirst();
}
public E removeFirst() {
  final Node<E> f = first;
  if (f == null)
    //链表空抛出异常
    throw new NoSuchElementException();
  return unlinkFirst(f);
}

Offer method, add elements at the end of the list

public boolean offer(E e) {
        return add(e);
    }
public boolean add(E e) {
        linkLast(e);
        return true;
    }

OfferFirst method, add a node in the head of the list, corresponding to the stack operation

public boolean offerFirst(E e) {
        addFirst(e);
        return true;
    }
public void addFirst(E e) {
        linkFirst(e);
    }

The offerLast method, adding elements at the end of the linked list, is essentially the same as the offer method

public boolean offerLast(E e) {
        addLast(e);
        return true;
    }
public void addLast(E e) {
        linkLast(e);
    }

peekFirst method, to view the head node of the linked list, equivalent to the peek method of Queue and Stack, empty list returns null

public E peekFirst() {
        final Node<E> f = first;
        return (f == null) ? null : f.item;
     }

peekLast method, check the tail node of the linked list, empty list returns null

public E peekLast() {
        final Node<E> l = last;
        return (l == null) ? null : l.item;
    }

pollFirst method, view and delete the head node of the linked list, empty list returns null

public E pollFirst() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }

pollLast view and delete the tail node of the linked list, empty list returns null

public E pollLast() {
        final Node<E> l = last;
        return (l == null) ? null : unlinkLast(l);
    }

Push method to add the head node position, Stack's push method

public void push(E e) {
        addFirst(e);
    }
public void addFirst(E e) {
        linkFirst(e);
    }

The pop method deletes the position element of the head node, the pop method of Stack

public E pop() {
        return removeFirst();
    }
public E removeFirst() {
        final Node<E> f = first;
        if (f == null)//链表空抛异常
            throw new NoSuchElementException();
        return unlinkFirst(f);
    }

The removeFirstOccurrence method finds the specified element from the head node and removes it

public boolean removeFirstOccurrence(Object o) {
        return remove(o);
    }
public boolean remove(Object o) {
        if (o == null) {//要移除的元素为null
            for (Node<E> x = first; x != null; x = x.next) {//从头查找,移除第一个为null元素
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {//依次遍历
                if (o.equals(x.item)) {//使用equals判断相等
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

The removeLastOccurrence method finds and removes the specified element from the tail node

public boolean removeLastOccurrence(Object o) {
        if (o == null) {//如果移除元素为null
            for (Node<E> x = last; x != null; x = x.prev) {//从后往前遍历
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = last; x != null; x = x.prev) {
                if (o.equals(x.item)) {//使用equals判断相等
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

The listIterator method returns a linked list iterator

public ListIterator<E> listIterator(int index) {
        checkPositionIndex(index);
        return new ListItr(index);
    }
//由于LinkedList是双向链表,所以可以双向遍历
private class ListItr implements ListIterator<E> {
        private Node<E> lastReturned;
        private Node<E> next;
        private int nextIndex;
  		//expectedModCount保存拿到迭代器时,LinkedList的modCount值,与快速失败有关
        private int expectedModCount = modCount;
  
  public boolean hasNext() {
            return nextIndex < size;
        }

        public E next() {
            checkForComodification();
            if (!hasNext())
                throw new NoSuchElementException();

            lastReturned = next;
            next = next.next;
            nextIndex++;
            return lastReturned.item;
        }

        public boolean hasPrevious() {
            return nextIndex > 0;
        }

        public E previous() {
            checkForComodification();
            if (!hasPrevious())
                throw new NoSuchElementException();

            lastReturned = next = (next == null) ? last : next.prev;
            nextIndex--;
            return lastReturned.item;
        }
  
  final void checkForComodification() {
            if (modCount != expectedModCount)//如果链表的modCount和拿到迭代器时modCount不同,说明在迭代过程中,链表进行了破坏结构的修改,那么应该直接抛出异常
                throw new ConcurrentModificationException();
        }
}

Vector

Class structure

As you can see, the class structure of Vector is exactly the same as ArrayList

Vector inherits AbstractList and implements the List interface

Vector implements RandomAccess interface, which can be accessed randomly

Vector implements the Cloneable interface and can use cloned objects

Vector implements the Serializable interface, which can be serialized

Attributes

//保存对象的数组
protected Object[] elementData;

//保存元素个数
protected int elementCount;

//增长因子
protected int capacityIncrement;

//定义的最大容量,为2的31次方-9
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

Constructor

public Vector(int initialCapacity, int capacityIncrement) {//指定初始容量和增长因子
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
  //直接把数组创建为初始化值大小
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }
public Vector(int initialCapacity) {
  //把增长因子设置为0
        this(initialCapacity, 0);
    }
public Vector() {
  //默认初始化大小为10
        this(10);
    }
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);
    }

method

Thread-safe method

The copyInto method copies the elements to the specified array

public synchronized void copyInto(Object[] anArray) {
        System.arraycopy(elementData, 0, anArray, 0, elementCount);
    }

The trimToSize method modifies the array of saved elements to the number of saved elements

public synchronized void trimToSize() {
        modCount++;
        int oldCapacity = elementData.length;
        if (elementCount < oldCapacity) {//如果元素个数比容量小
            elementData = Arrays.copyOf(elementData, elementCount);
        }
    }

The ensureCapacity method is used to ensure the size of the array when adding elements

public synchronized void ensureCapacity(int minCapacity) {
        if (minCapacity > 0) {
            modCount++;
            ensureCapacityHelper(minCapacity);
        }
    }

private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)//如果需要的最小容量大于数组大小
          //扩容
            grow(minCapacity);
    }

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
  //如果指定了增长因子而且增长因子>0那么新容量就等于原容量+增长因子,否则就是原容量的二倍
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

The setSize method sets the size of the vector

public synchronized void setSize(int newSize) {
        modCount++;
        if (newSize > elementCount) {//如果新容量比原容量大,多的元素全为null
            ensureCapacityHelper(newSize);
        } else {
          //新容量比原容量小
            for (int i = newSize ; i < elementCount ; i++) {
                elementData[i] = null;
            }
        }
        elementCount = newSize;
    }

removeElementAt remove the element at the specified position

public synchronized void removeElementAt(int index) {
        modCount++;
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                     elementCount);
        }
        else if (index < 0) {
            throw new ArrayIndexOutOfBoundsException(index);
        }
  //要移动的元素个数
        int j = elementCount - index - 1;
        if (j > 0) {
            System.arraycopy(elementData, index + 1, elementData, index, j);
        }
        elementCount--;
        elementData[elementCount] = null; /* to let gc do its work */
    }

insertElementAt insert the element at the specified position

public synchronized void insertElementAt(E obj, int index) {
        modCount++;
        if (index > elementCount) {
            throw new ArrayIndexOutOfBoundsException(index
                                                     + " > " + elementCount);
        }
  //确保容量
        ensureCapacityHelper(elementCount + 1);
        System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
        elementData[index] = obj;
        elementCount++;
    }

addElement adds an element at the end

public synchronized void addElement(E obj) {
        modCount++;
  //确保容量
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = obj;
    }

removeElement removes the specified element

public synchronized boolean removeElement(Object obj) {
        modCount++;
        int i = indexOf(obj);
        if (i >= 0) {
            removeElementAt(i);
            return true;
        }
        return false;
    }

removeAllElements remove all elements

public synchronized void removeAllElements() {
        modCount++;
        // Let gc do its work
        for (int i = 0; i < elementCount; i++)
            elementData[i] = null;

        elementCount = 0;
    }

get get the specified position element

public synchronized E get(int index) {
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);

        return elementData(index);
    }

set replaces the specified position element

public synchronized E set(int index, E element) {
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

The add method adds an element. The difference from the addElement method is only the return value.

public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

remove remove the tail element

public boolean remove(Object o) {
        return removeElement(o);
    }

add add element at specified position

public void add(int index, E element) {
        insertElementAt(element, index);
    }

remove remove the element at the specified position

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;
    }

listIterator to obtain vector iterator, you can traverse forward and backward

public synchronized ListIterator<E> listIterator() {
        return new ListItr(0);
    }
final class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) {
            super();
            cursor = index;
        }

        public boolean hasPrevious() {
            return cursor != 0;
        }

        public int nextIndex() {
            return cursor;
        }

        public int previousIndex() {
            return cursor - 1;
        }

        public E previous() {
            synchronized (Vector.this) {
                checkForComodification();
                int i = cursor - 1;
                if (i < 0)
                    throw new NoSuchElementException();
                cursor = i;
                return elementData(lastRet = i);
            }
        }

        public void set(E e) {
            if (lastRet == -1)
                throw new IllegalStateException();
            synchronized (Vector.this) {
                checkForComodification();
                Vector.this.set(lastRet, e);
            }
        }

        public void add(E e) {
            int i = cursor;
            synchronized (Vector.this) {
                checkForComodification();
                Vector.this.add(i, e);
                expectedModCount = modCount;
            }
            cursor = i + 1;
            lastRet = -1;
        }
    }

It can be seen that the source codes of Vector and ArrayList are basically the same, but Vector is thread-safe, and Vector and ArrayList are slightly different in expansion. If Vector specifies a growth factor, then the new capacity is the original capacity + growth factor ArrayList is directly expanded twice the original capacity

Guess you like

Origin www.cnblogs.com/moyuduo/p/12702275.html