ArrayList详解
1.ArrayList继承AbstractList,该类的父类AbstractCollection实现了Collection接口。
2.RandomAccess:是一个标识,其内部无任何定义,表名该类支持随机访问。
3.Cloneable:能被克隆,实现了clone()方法,浅拷贝。
4.Serializable:支持序列化,能通过序列化去传输。
1.成员变量
//默认初始容量大小 private static final int DEFAULT_CAPACITY = 10; //共享空数组 private static final Object[] EMPTY_ELEMENTDATA = {}; //有初始容量的共享空数组 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //保存数据的数组 transient Object[] elementData; //元素个数 private int size;
2.构造器
//参数为集合的长度 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() { //创建有初始容量的空数组 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } //参数为Collection或其子类对象 public ArrayList(Collection<? extends E> c) { //将集合转为数组 elementData = c.toArray(); if ((size = elementData.length) != 0) { //判断数组的类型是否为Object if (elementData.getClass() != Object[].class) //若不是Object将其转为Object类型 elementData = Arrays.copyOf(elementData, size, Object[].class); } else { //若集合长度为0,创建空数组 this.elementData = EMPTY_ELEMENTDATA; } }
3.主要方法
//该方法将数组长度改为集合中存在元素数量 public void trimToSize() { modCount++; //若当前元素数量小于数组长度:为0则创建空数组,为其他值将数组长度压缩为当前集合中元素的数量。 if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }
扩容机制,以添加单个元素为例
public boolean add(E e) { modCount++; //调用私有方法添加元素 add(e, elementData, size); return true; } private void add(E e, Object[] elementData, int s) { //若当前元素数量已经与集合长度相同,就进行扩容,调用grow() if (s == elementData.length) elementData = grow(); elementData[s] = e; size = s + 1; } private Object[] grow() { return grow(size + 1); } private Object[] grow(int minCapacity) { int oldCapacity = elementData.length; if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //minCatacity为假若成功添加后元素数量,oldCapacity为当前集合长度,若minCapacity - oldCapacity < oldCapacity >> 1 ,newCapacity = oldCapacity >> 1 + oldCapacity,也就是1.5倍。否则newCapacity = minCapacity + oldCapacity int newCapacity = ArraysSupport.newLength(oldCapacity, minCapacity - oldCapacity, /* minimum growth */ oldCapacity >> 1 /* preferred growth */); return elementData = Arrays.copyOf(elementData, newCapacity); } else { //若数组为空,执行下述代码 return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)]; } }
int size():返回集合中元素的数量
boolean isEmpty():判断集合是否为空
boolean contains(Object o):判断集合是否包含指定元素
int indexOf(Object o):返回集合中首次出现元素o的索引
int lastIndexOf(Object o):返回集合中最后一次出现元素o的索引
Object[] toArray():将结合转为Object类型数组
<T> T[] toArray(T[] a):将集合转为指定类型数组
E get(int index):返回指定索引处元素
E set(int index, E element):用指定元素替换指定索引处的元素
boolean add(E e):在末尾添加元素
void add(int index, E element):在指定位置处添加元素
E remove(int index):移除指定索引处元素并返回该元素
boolean remove(Object o):移除指定元素
void removeRange(int fromIndex, int toIndex):移除指定索引范围内元素,左闭右开
void clear():清除集合中的所有元素
boolean addAll(Collection<? extends E> c):将指定集合添加至该集合的尾部
最后:向 ArrayList 添加大量元素之前最好先使用ensureCapacity
方法,以减少增量重新分配的次数。
LinkedList:
1.AbstractSequentialList:定义了关于链表的一些操作
2.Deque:双端队列的缩写double ended queue
所以LinkedList既可作为链表使用,也可作为队列使用。(增删速度快,查询速度慢)
作为队列:
入队列:
public boolean add(E e) { linkLast(e); return true; } void linkLast(E e) { //l为队列的最后一个节点 final Node<E> l = last; //创建新节点newNode,其前一个节点是l,后一个节点为空 final Node<E> newNode = new Node<>(l, e, null); //更新队列的最后一个节点 last = newNode; //如果l为空,说明此时是一个空队列,更新first节点 if (l == null) first = newNode; //LinkedList是双向链表,所以更新l的next的节点使其指向新节点 else l.next = newNode; size++; modCount++; }
出队列
public E poll() { final Node<E> f = first; //判断队列的首节点是否为空:为空则没有节点可出队列,直接返回空。不为空则删除队列的第一个节点 return (f == null) ? null : 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; //让首节点的next域为空 f.next = null; // help GC //更新队列的首节点 first = next; if (next == null) last = null; else next.prev = null; size--; modCount++; return element; }
作为栈
入栈
//始终在头部插入,就能保证第一个节点为刚入栈 public void push(E e) { addFirst(e); } public void addFirst(E e) { linkFirst(e); } 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++; }
出栈
//同样的道理:出栈时始终删除第一个元素,可保证先入后出 public E pop() { return removeFirst(); } 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; }