Java集合框架分析(二)——List集合之ArrayList源码分析
因为复习集合框架的本意是要学习集合框架,因此我接下来做三个任务,分析源码,自己实现对应的数据结构,实现下集合中的大部分常用方法。
上一章说到List的特点:元素是有序的并且元素是可以重复的,因为该集合有索引,讲到这里学过数据结构的人就知道了其实这就是一个线性表,确实list的底层数据结构就是线性表。
我们来看List接口的实现类,最常见的大概就四种,ArrayList, LinkedList, Vector, Stack.,这里我们就对ArrayList和LinkedList进行分析因为他们是最常用的并且代表了线性表的两个典型实现,顺序表(数组)和链表。
首先是ArrayList,它的底层数据结构就是数组,因为每个元素有索引,所以他的特点是:查询快,但是增删慢,而且线程不同步(多线程还没有深入学习,这里不做分析)。
好了我们就从源码开始分析。
首先看ArrayList的构造函数
//默认的构造函数 public ArrayList() { this(10); } //initialCapacity是指默认的容量,也就是数组容量大小 public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } //创建一个包含Collection的ArrayList public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); size = elementData.length; if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); }
从上我们可以知道其实ArrayList其实就是一个动态数组,当数据超出容量时会自动扩容,从默认的构造函数可以知道他的起始默认长度是10.其中elementData和size是关键,我们看看elementData的定义:
Object[] elementData 显然她是一个Object类型的动态数组,用来保存元素,他的容量会根据具体的元素大小而动态的增长。
而size从上可以看到 size = elementData.length,其实就是动态数组的实际大小。
接下来把源码贴上来,其中已经加上了我的注释:
package com.code; import java.util.AbstractList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.ConcurrentModificationException; import java.util.LinkedList; import java.util.List; import java.util.RandomAccess; import java.util.Vector; public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { // 版本序列号 private static final long serialVersionUID = 8683452581122892189L; // 保存元素的动态数组 private transient Object[] elementData; // 动态数组的实际大小 private int size; // 带容量大小的构造函数 public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); this.elementData = new Object[initialCapacity]; } // 默认的构造函数,默认大小是10 public ArrayList() { this(10); } // 创建一个包含collection的ArrayList public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); size = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } // 将当前的数组容量设置为实际元素的个数 public void trimToSize() { modCount++; int oldCapacity = elementData.length; if (size < oldCapacity) { elementData = Arrays.copyOf(elementData, size); } } // 动态数组扩容的方法,关键!这是和Vector的区别之一,算法是新的数组容量=(旧的数组容量*3)/2+1 public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3) / 2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } } // 返回元素的实际个数也就是ArrayList的实际大小 public int size() { return size; } // 实现的Collection的方法,判断是否为空 public boolean isEmpty() { return size == 0; } // 看是否包含一个对象,调用的是indexOf方法 public boolean contains(Object o) { return indexOf(o) >= 0; } // 根据索引查找对象,返回的是元素的索引值 public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i] == null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; } // 这是反向查找,具体什么作用未知 public int lastIndexOf(Object o) { if (o == null) { for (int i = size - 1; i >= 0; i--) if (elementData[i] == null) return i; } else { for (int i = size - 1; i >= 0; i--) if (o.equals(elementData[i])) return i; } return -1; } // 克隆函数 public Object clone() { try { ArrayList<E> v = (ArrayList<E>) super.clone(); // 将当前元素复制到v中 v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(); } } // 返回ArrayList的Object数组 public Object[] toArray() { return Arrays.copyOf(elementData, size); } // public <T> T[] toArray(T[] a) { // 如果数组a的个数小于ArrayList的实际元素个数 if (a.length < size) // 创建一个新的数组 return (T[]) Arrays.copyOf(elementData, size, a.getClass()); // 将a的元素复制到新的数组中 System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } // Positional Access Operations // 根据索引值获取对应的元素 public E get(int index) { RangeCheck(index); return (E) elementData[index]; } // 修改索引位置的元素的值 public E set(int index, E element) { RangeCheck(index); E oldValue = (E) elementData[index]; elementData[index] = element; return oldValue; } // 添加一个元素到数组的末尾,实现原理是数组的长度加1 public boolean add(E e) { ensureCapacity(size + 1); // Increments modCount!! elementData[size++] = e; return true; } // 根据索引来添加指定元素 public void add(int index, E element) { if (index > size || index < 0) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); ensureCapacity(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } // 根据索引值来移除指定的元素,,返回的是移除的值 public E remove(int index) { RangeCheck(index); modCount++; E oldValue = (E) elementData[index]; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index + 1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work return oldValue; } // 删除ArrayList中的指定元素 public boolean remove(Object o) { 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; } // 快速删除指定索引的元素,和remove方法相比少了RangeCheck(index);这个步骤 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; // Let gc do its work } // 清空所有元素,就是遍历元素把所有元素变成null public void clear() { modCount++; // Let gc do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; } // 将集合c加到ArrayList中 public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacity(size + numNew); // Increments modCount System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; } // 添加集合c到指定索引位置 public boolean addAll(int index, Collection<? extends E> c) { if (index > size || index < 0) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); Object[] a = c.toArray(); int numNew = a.length; ensureCapacity(size + numNew); // Increments modCount int numMoved = size - index; if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; } // 删除fromIndex到toIndex之间的所有元素 protected void removeRange(int fromIndex, int toIndex) { modCount++; int numMoved = size - toIndex; System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved); // Let gc do its work int newSize = size - (toIndex - fromIndex); while (size != newSize) elementData[--size] = null; } private void RangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); } // 将ArrayList的“容量,所有的元素值”都写入到输出流中 private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Write out element count, and any hidden stuff int expectedModCount = modCount; s.defaultWriteObject(); // Write out array length s.writeInt(elementData.length); // Write out all elements in the proper order. for (int i = 0; i < size; i++) s.writeObject(elementData[i]); if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } } // 先将ArrayList的“容量”读出,然后将“所有的元素值”读出 private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in size, and any hidden stuff s.defaultReadObject(); // Read in array length and allocate array int arrayLength = s.readInt(); Object[] a = elementData = new Object[arrayLength]; // Read in all elements in the proper order. for (int i = 0; i < size; i++) a[i] = s.readObject(); } }
总的来说
(1)ArrayList就是一个动态数组的实现类。容量不足的时候会设置新的容量。新容量=(旧的容量*3)/2+1
(2)源码的最后部分是对io的写入和读取
好了先分析到这里,妈蛋这个点了明天,不对应该是今天还满课,明天还要考线代。。。