Análisis de código fuente ArrayList, LinkedList y Vector

Análisis de código fuente ArrayList, LinkedList y Vector

Lista de arreglo

ArrayList es una clase subyacente que usa matrices para almacenar objetos, pero no es una clase de colección segura para subprocesos

Relación de estructura de clase de ArrayList

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

ArrayList implementa la interfaz Lista, que define algunos métodos para agregar y eliminar listas a través de subíndices.

ArrayList implementa la interfaz RandomAccess. Esta interfaz es una interfaz de marca. No hay ningún método en la interfaz. La capa inferior de ArrayList utiliza matrices para almacenar objetos. Por supuesto, se puede acceder al azar a través de subíndices. La velocidad será rápida, pero la adición y eliminación de elementos será lenta, y LinkedList se implementa a través de una lista vinculada. No implementa la interfaz RandomAccess, que es lenta durante la consulta pero aumenta la velocidad de eliminación.

Entonces, cuando use una colección para atravesar una gran cantidad de datos, primero puede usar instanceof para determinar si la colección implementa 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 implementa la interfaz Cloneable, puede llamar legalmente método clone, si no implementar la interfaz Cloneable, entonces lanza CloneNotSupporteddException , ver

ArrayList implementa la interfaz serializable, que puede serializar objetos para transmisión o persistencia, ver detalles

Atributos

//序列化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 proporciona tres constructores, uno es un constructor que especifica el tamaño de inicialización, uno es un constructor sin tamaño de inicialización predeterminado de parámetro y uno es un constructor que utiliza una inicialización de colección

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

Agregar elemento

Agregar elementos al final de la matriz

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

Agregar elemento en la posición especificada

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

Eliminar elemento

Eliminar elementos según subíndice

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

Eliminar elementos por valor

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 realiza la operación modCount + 1 durante la adición, configuración y eliminación. Esta propiedad está relacionada con la falla rápida. Cuando el objeto crea un objeto Iterator, asignará modCount a esperadoModCount. Al usar Iterator para atravesar, si se encuentra el modCount del objeto No es igual a lo esperadoModCount, lanzará directamente la excepción ConcurrentModificationException

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

Ocurrencia: cuando atraviesa Iterator, si el modCount del objeto y elModCount esperado no son iguales, se generará una excepción, principalmente en estas situaciones

  • Al usar el iterador para recorrer, agregar, eliminar y otras operaciones que destruyen la estructura
  • En un entorno de subprocesos múltiples, cuando un subproceso está atravesando, otro subproceso realiza operaciones como agregar y quitar para destruir la estructura

A través del aprendizaje del código fuente, descubrí que el método set no aumentó modCount, ¿por qué? ¿Es posible que un hilo use iterador para atravesar, y otro hilo cambie el elemento de una posición, Iterator no necesita lanzar una excepción? Si lo sabes, ¡por favor, ilumíname!

Lista enlazada

Estructura de clase LinkedList

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

LinkedList hereda AbstractSequentialList para lograr acceso aleatorio a través de Iterator

LinkedList implementa la interfaz de Lista para realizar operaciones como la adición y eliminación

LinkedList implementa DeQue, lo que permite poner en cola y en cola en ambos extremos de la cola, por lo que puede usar LinkedList como cola o pila

LinkedList implementa Cloneable, que puede clonar objetos rápidamente a través de clone

LinkedList implementa la interfaz serializable, que puede serializar LinkedList para operaciones de transmisión

Constructor

public LinkedList() {
    }

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

Atributos

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

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

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

Nodo

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

Puede ver que LinkedList es una lista doblemente vinculada

Método

Deque es una lista vinculada de doble extremo, es decir, la lista vinculada se puede usar como una pila y cola

El método getFirst es equivalente al método del elemento en la Cola. Si la cola está vacía, se genera una excepción

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

método getLast

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

El método removeFirst es equivalente al método remove de la cola. Elimina el elemento head. Si la cola está vacía, se genera una excepción.

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

método removeLast, si el equipo está vacío, lanza una excepción

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

El método addFirst es equivalente al método push en 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++;
}

Método addLast, equivalente al método add en 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++;
    }

El método add es reescribir el método en AbstractList, es decir, agregar elementos a la Lista

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

El método remove elimina el elemento especificado de la lista vinculada

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

El método addAll agrega los elementos de la colección especificada a la lista vinculada

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

El método clear borra la lista vinculada, pero modCount no la borrará

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

obtener el método para obtener el elemento de subíndice especificado, el subíndice ilegal produce una excepción

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

El método set establece el valor del elemento de subíndice especificado. El subíndice ilegal arroja una excepción. ¿El método set no es modCount ++? porque

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

agregar método, especificar el subíndice para agregar elementos, el subíndice ilegal arroja una excepción

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

eliminar método, eliminar el elemento de subíndice especificado, el subíndice ilegal produce una excepción

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

El método peek para obtener el nodo principal de la lista vinculada puede ser el método Queue / Stack, el método Queue obtiene el elemento jugador del equipo y el método Stack obtiene el elemento superior

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

método de elemento, para obtener el nodo principal de la lista enlazada, diferente del método peek, si la cola está vacía, se genera una excepción

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

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

El método de sondeo elimina el nodo principal de la lista vinculada. Si la lista vinculada está vacía, se devuelve un valor nulo.

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

El método remove elimina el nodo principal de la lista vinculada

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

Método de oferta, agregue elementos al final de la lista

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

Método OfferFirst, agregue un nodo en el encabezado de la lista, correspondiente a la operación de pila

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

El método offerLast, que agrega elementos al final de la lista vinculada, es esencialmente el mismo que el método de oferta

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

Método peekFirst, para ver el nodo principal de la lista vinculada, equivalente al método peek de Queue and Stack, la lista vacía devuelve nulo

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

Método peekLast, verifique el nodo de cola de la lista vinculada, la lista vacía devuelve nulo

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

método pollFirst, vea y elimine el nodo principal de la lista vinculada, la lista vacía devuelve nulo

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

Última vista y eliminar el nodo de cola de la lista vinculada, la lista vacía devuelve nulo

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

Método de inserción para agregar la posición del nodo principal, método de inserción de la pila

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

El método pop elimina el elemento de posición del nodo principal, el método pop de Stack

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

El método removeFirstOccurrence encuentra el elemento especificado del nodo principal y lo elimina

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

El método removeLastOccurrence encuentra y elimina el elemento especificado del nodo de cola

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

El método listIterator devuelve un iterador de lista vinculada

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

Estructura de clase

Como puede ver, la estructura de clases de Vector es exactamente la misma que ArrayList

Vector hereda AbstractList e implementa la interfaz List

Vector implementa la interfaz RandomAccess, a la que se puede acceder aleatoriamente

Vector implementa la interfaz clonable y puede usar objetos clonados

Vector implementa la interfaz serializable, que puede ser serializada

Atributos

//保存对象的数组
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);
    }

Método

Método a prueba de hilos

El método copyInto copia los elementos en la matriz especificada

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

El método trimToSize modifica la matriz de elementos guardados a la cantidad de elementos guardados

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

El método allowCapacity se usa para garantizar el tamaño de la matriz al agregar elementos

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

El método setSize establece el tamaño del 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 elimina el elemento en la posición especificada

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 inserta el elemento en la posición especificada

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 agrega un elemento al final

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

removeElement elimina el elemento especificado

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

removeAllElements elimina todos los elementos

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

        elementCount = 0;
    }

obtener obtener el elemento de posición especificado

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

        return elementData(index);
    }

set reemplaza el elemento de posición especificado

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

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

El método add agrega un elemento. La diferencia con el método addElement es solo el valor de retorno.

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

eliminar eliminar el elemento de cola

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

agregar agregar elemento en la posición especificada

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

eliminar eliminar el elemento en la posición especificada

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 para obtener el iterador vectorial, puede recorrer hacia adelante y hacia atrás

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

Se puede ver que los códigos fuente de Vector y ArrayList son básicamente los mismos, pero Vector es seguro para subprocesos y Vector y ArrayList son ligeramente diferentes en expansión. Si Vector especifica un factor de crecimiento, entonces la nueva capacidad es la capacidad original + factor de crecimiento ArrayList se expande directamente dos veces la capacidad original

Supongo que te gusta

Origin www.cnblogs.com/moyuduo/p/12702275.html
Recomendado
Clasificación