我习惯了无所谓,却不是真的什么都不在乎。 请关注:源码猎人
目录
简介
LinkedList 源码解读
LinkedList父类 AbstractSequentialList 抽象类
AbstractSequentialList 构造函数
AbstractSequentialList 方法
LinkedList 类
LinkedList 属性
LinkedList 构造函数
LinkedList 方法
LinkedList 内部类
Vector 向量 源码解读
Vector属性
Vector构造函数
Vector方法
Vector内部类
Stack 栈 源码解读
Stack 方法
常见面试题
LinkedList是特殊List,为什么说它特殊?从类图上就可以看出来,它是List、Queue(Deque继承Queue)的实现,相比ArrayList多实现了Deque接口而少实现了RandomAccess接口,从名字就可以看除内部使用链表结构;Vector 向量是线程安全的动态数组,跟ArrayList很相似,JDK1.0中添加Vector类,Vector一样可以维护插入顺序,但Vector包含了许多传统的方法,这些方法不属于集合框架;Stack栈是一种只能在一端进行插入或删除操作的线性表,先进后出表。
AbstractSequentialList继承自AbstractList。AbstractSequentialList是在迭代器的基础上实现的get、set、add和remove方法。并且AbstractSequentialList 只支持按次序访问,而不像 AbstractList 那样支持随机访问
通过listIterator确定位置,调用next取值
// 修改指定位置的元素为新值 public E set(int index, E element) { try { ListIterator<E> e = listIterator(index); E oldVal = e.next(); e.set(element); return oldVal; } catch (NoSuchElementException exc) { throw new IndexOutOfBoundsException("Index: "+index); } }覆盖新值返回旧值
// 添加元素到指定位置 public void add(int index, E element) { try { listIterator(index).add(element); } catch (NoSuchElementException exc) { throw new IndexOutOfBoundsException("Index: "+index); } }如果指定位置有值,将当前处于该位置的后续元素移到右边
// 删除 public E remove(int index) { try { ListIterator<E> e = listIterator(index); E outCast = e.next(); e.remove(); return outCast; } catch (NoSuchElementException exc) { throw new IndexOutOfBoundsException("Index: "+index); } }listIterator 取值,调用listIterator删除元素
// 在指定位置添加一个线性集合 public boolean addAll(int index, Collection<? extends E> c) { try { boolean modified = false; ListIterator<E> e1 = listIterator(index); Iterator<? extends E> e2 = c.iterator(); while (e2.hasNext()) { e1.add(e2.next()); modified = true; } return modified; } catch (NoSuchElementException exc) { throw new IndexOutOfBoundsException("Index: "+index); } } // 获取迭代器 public Iterator<E> iterator() { return listIterator(); } // 根据索引获取listIterator public abstract ListIterator<E> listIterator(int index);AbstractSequencetialList中的增删改查都是用ListIterator完成,子类必须实现listIterator(int index)方法
实现List<E>, Deque<E>接口,继承AbstractSequentialList<E>抽象类
从构造函数可以看出初始默认值为0
LinkedList 双向链表基础方法
// 在头上增加元素 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; // 长度加1 size++; // 修改次数加1 modCount++; } // 在尾部追加元素 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; // 长度加1 size++; // 修改次数加1 modCount++; } // 在succ节点前插入元素 void linkBefore(E e, Node<E> succ) { final Node<E> pred = succ.prev; // 构建新元素,新节点下级指向succ final Node<E> newNode = new Node<>(pred, e, succ); // succ上一个节点指向新节点 succ.prev = newNode; // succ原来上级节点的next指向新节点 if (pred == null) first = newNode; else pred.next = newNode; // 长度加1 size++; // 修改次数加1 modCount++; } // 删除头节点 private E unlinkFirst(Node<E> f) { final E element = f.item; // 获取下一个节点 final Node<E> next = f.next; f.item = null; f.next = null; // help GC // 头节点指向next first = next; if (next == null) last = null; else next.prev = null; // 长度减1 size--; // 修改次数加1 modCount++; return element; } // 删除尾节点 private E unlinkLast(Node<E> l) { 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; // 长度减1 size--; // 修改次数加1 modCount++; return element; } // 删除节点 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; } // 下级节点的上级指向当前节点的上级 if (next == null) { last = prev; } else { next.prev = prev; x.next = null; } // 清空当前节点 x.item = null; size--; modCount++; return element; } // 索引取值 Node<E> node(int 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; } }LinkedList 添加
// 添加元素 public boolean add(E e) { // 默认尾部追加 linkLast(e); return true; } // 头部添加 public void addFirst(E e) { linkFirst(e); } // 尾部添加 public void addLast(E e) { linkLast(e); }LinkedList 删除
// 移除头元素 public E removeFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return unlinkFirst(f); } // 移除尾元素 public E removeLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return unlinkLast(l); } // 删除元素 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 { // 遍历链表找到equals一样的元素 for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) { unlink(x); // 只会删除第一个 return true; } } } return false; }LinkedList 搜索
// 获取头节点 public E getFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return f.item; } // 获取尾节点 public E getLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return l.item; } // 根据所有取值 public E get(int index) { checkElementIndex(index); // 调用node(index) return node(index).item; }
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; } }Node<E>用来包装实际元素值,并且提供两个指针prev、next。
从构造函数中可以看出创建时就初始化了10个长度的元素数组,增长长度只有第一个构造函数有设置值,其他的都为0
设置长度
public synchronized void setSize(int newSize) { // 修改次数加1 modCount++; // 判断是否需要扩容 if (newSize > elementCount) { ensureCapacityHelper(newSize); } else { // 参数以后的元素清空掉 for (int i = newSize ; i < elementCount ; i++) { elementData[i] = null; } } elementCount = newSize; } private void ensureCapacityHelper(int minCapacity) { // 判断新长度是否大于原数组长度,大于则扩容 if (minCapacity - elementData.length > 0) grow(minCapacity); }新长度小于元素个数时阶段原数组,新长度大于元素数组长度时使用新长度扩容
扩容
private void grow(int minCapacity) { // 获取原长度 int oldCapacity = elementData.length; // 获取新长度 // 增长长度不为0时 新长度=原长度+增长长度 // 增长长度不为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); } private static int hugeCapacity(int minCapacity) { // 长度小于0则抛异常 if (minCapacity < 0) throw new OutOfMemoryError(); // 长度大于默认最大值取Integer最大值 return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }Vector扩容比较特殊,不像ArrayList,ArrayList没有增长长度正常情况下扩容只能为原长度的1.5倍,而Vector在扩容时,先判断增长长度是否为0,不为0时使用增长长度,为0时原长度乘以2
查找元素 从前往后找
public int indexOf(Object o) { return indexOf(o, 0); } public synchronized int indexOf(Object o, int index) { if (o == null) { // index为起始位置 for (int i = index ; i < elementCount ; i++) // 查找元素为空 if (elementData[i]==null) return i; } else { // index为起始位置 for (int i = index ; i < elementCount ; i++) // 查找equals一样的元素 if (o.equals(elementData[i])) return i; } // 没有找到返回-1 return -1; }从后往前找
public synchronized int lastIndexOf(Object o) { return lastIndexOf(o, elementCount-1); } public synchronized int lastIndexOf(Object o, int index) { // 判断index是否超过元素个数 if (index >= elementCount) throw new IndexOutOfBoundsException(index + " >= "+ elementCount); if (o == null) { // 从后往前找 for (int i = index; i >= 0; i--) if (elementData[i]==null) return i; } else { // 从后往前找 for (int i = index; i >= 0; i--) if (o.equals(elementData[i])) return i; } // 没有找到返回-1 return -1; }元素数组操作
public Enumeration<E> elements() { // 每次调用此方法都会有一个新对象 return new Enumeration<E>() { int count = 0; public boolean hasMoreElements() { return count < elementCount; } public E nextElement() { // 虽然方法上没加锁,但是这儿加了,锁的是当前对象 synchronized (java.util.Vector.this) { if (count < elementCount) { return elementData(count++); } } throw new NoSuchElementException("Vector Enumeration"); } }; }这里顺带介绍Enumeration,Enumeration接口中定义了一些方法,通过这些方法可以枚举(一次获得一个)对象集合中的元素。这种传统接口已被迭代器取代,虽然Enumeration 还未被遗弃,但在现代代码中已经被很少使用了。
前后第一个元素
public synchronized E firstElement() { // 数组为空时抛异常 if (elementCount == 0) { throw new NoSuchElementException(); } return elementData(0); } public synchronized E lastElement() { // 数组为空时抛异常 if (elementCount == 0) { throw new NoSuchElementException(); } // 取最后一个元素 return elementData(elementCount - 1); }索引找元素
E elementData(int index) { // 通过索引直接从数组中取值 return (E) elementData[index]; } public synchronized E elementAt(int index) { // 判断索引是否大于元素个数 if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } return elementData(index); } public synchronized void setElementAt(E obj, int index) { // 超过元素个数抛异常 if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } // 根据索引设值 elementData[index] = obj; }删除指定位置上的元素
public synchronized void removeElementAt(int index) { modCount++; // 判断指定索引是否超过元素个数 if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } // 索引不能小于0 else if (index < 0) { throw new ArrayIndexOutOfBoundsException(index); } // 索引位置以后的元素前向前移动 int j = elementCount - index - 1; if (j > 0) { System.arraycopy(elementData, index + 1, elementData, index, j); } // 元素个数减1 elementCount--; // 最后一个元素置空 elementData[elementCount] = null; /* to let gc do its work */ }在指定位置上插入元素
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++; }追加元素
public synchronized void addElement(E obj) { modCount++; // 判断是否需要扩容 ensureCapacityHelper(elementCount + 1); // 末尾增加元素 elementData[elementCount++] = obj; }删除元素
public synchronized boolean removeElement(Object obj) { modCount++; // 找到元素位置 int i = indexOf(obj); // 存在就删除 if (i >= 0) { removeElementAt(i); return true; } return false; }删除所有元素
public synchronized void removeAllElements() { modCount++; // 遍历索引元素,依次置空 for (int i = 0; i < elementCount; i++) elementData[i] = null; elementCount = 0; }添加删除
public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; } public boolean remove(Object o) { return removeElement(o); }添加删除方法主要是还使用上面的方法,这里就不在赘述
沿用父类方法
public synchronized boolean containsAll(Collection<?> c) { return super.containsAll(c); } public synchronized boolean removeAll(Collection<?> c) { return super.removeAll(c); } public synchronized boolean retainAll(Collection<?> c) { return super.retainAll(c); } public synchronized boolean equals(Object o) { return super.equals(o); } public synchronized int hashCode() { return super.hashCode(); } public synchronized String toString() { return super.toString(); }父类中的方法参照List接口篇
自有方法很少,主要的就入栈出栈
1、ArrayList和LinkedList 的区别是什么?
数据接口实现:ArrayList:是动态数组数据结构实现的,LinkedList是基于双向链表数据结构实现的.随机访问效率:ArrayList比LinkedList访问效率高,因为LinkedList是基于线性数据存储的方式,所以要移动指针依次查找数据.增加和访问的效率:在非首尾添加数据,LinkedList要比ArrayList要高,因为ArrayLIst是基于数组实现的他的添加要影响数组的数据下标.2、LinkedList 可以添加空元素吗?
LinkedList 虽然实现了队列接口但是它并不是正在意义上的队列,队列不能存放空元素,原因是取的时候有争议,而LinkedList更多意义上是List,一般无视了这个问题,它可以向ArrayList一样添加空元素。
3、ArrayList和Vector 的区别是什么?
Vector是线程安全的,也就是说是它的方法之间是线程同步的,而ArrayList是线程序不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用Vector,因为不需要我们自己再去考虑和编写线程安全的代码。ArrayList与Vector都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加ArrayList与Vector的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector默认增长为原来两倍,而ArrayList增长为原来的1.5倍。ArrayList与Vector都可以设置初始的空间大小,Vector还可以设置增长的空间大小,而ArrayList没有提供设置增长空间的方法。