Java集合框架(2)—ArrayList源码分析
2017-01-16 23:41
316 查看
ArrayList是Java容器类中最重要的类之一,我将根据ArrayList源码,结合自己的认识,学习ArrayList的实现,以点破面,以期对Java集合类有一个全面的深入。
以下是ArrayList源代码的outline:
1,类定义:
ArrayList继承AbstractList,实现List,RandomAccess,Cloneable,java.io.Serializable接口
2,elementData
ArrayList实际数据存储结构,transient是一个关键词:Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。
3,size
ArrayList包含元素的个数
4,构造器
5,trimToSize
将ArrayList的容量压缩到目前所包含元素的个数,即最小化容量
6,扩容相关
ArrayList最大的特征就是可以在初始化之后仍能改变大小。因此改变容量是其核心操作。与扩容相关的方法和变量如下:
变量:
1)size:size自然是非常关心的域
2)MAX_ARRAY_SIZE:最大容量,由JVM设定,
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
Integer,MAX_VALUE是2^32-1,至于为什么要再减8,不是很清楚。
3)minCapacity:经常作为参数传入扩容函数,是扩容后的容积不能小于这个值。
方法:
7,整体操作
8,数据操作
9,流操作
ObjectInputStream和ObjectOutputStream是针对类对象的输入输出流,配合ArrayList可以组成灵活的操作,ArrayList有两个和他们相关的方法:
10,List转化与ListIterator
11,函数式编程相关
在Java1.8中加入了对函数式编程的一些支持,ArrayList也有一些相应方法,需要理解函数相关接口才好理解。暂跳过。
在http://ifeve.com/有很多相关的中文博客
12,sort
跟据Comparator进行排序
总结,通读了一遍ArrayList源码,发现了不少精巧的设计,加深了对容器类的理解。后续要继续努力学习其他源码——2017/1/16
以下是ArrayList源代码的outline:
1,类定义:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
ArrayList继承AbstractList,实现List,RandomAccess,Cloneable,java.io.Serializable接口
2,elementData
transient Object[] elementData;
ArrayList实际数据存储结构,transient是一个关键词:Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。
3,size
private int size;
ArrayList包含元素的个数
4,构造器
有参构造器,设置了初始容量 public ArrayList(int initialCapacity) 无参构造器,初始容量默认为10 public ArrayList() 元素是集合类的构造器 public ArrayList(Collection<? extends E> c)
5,trimToSize
public void trimToSize() { modCount++; if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }
将ArrayList的容量压缩到目前所包含元素的个数,即最小化容量
6,扩容相关
ArrayList最大的特征就是可以在初始化之后仍能改变大小。因此改变容量是其核心操作。与扩容相关的方法和变量如下:
变量:
1)size:size自然是非常关心的域
2)MAX_ARRAY_SIZE:最大容量,由JVM设定,
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
Integer,MAX_VALUE是2^32-1,至于为什么要再减8,不是很清楚。
3)minCapacity:经常作为参数传入扩容函数,是扩容后的容积不能小于这个值。
方法:
//保证容量不小于minCapacity,如果目前容量小于,会调用ensureExplicitCapacity()扩容 public void ensureCapacity(int minCapacity) private void ensureCapacityInternal(int minCapacity) //执行扩容到minCapacity,内部是调用grow()函数扩容 private void ensureExplicitCapacity(int minCapacity{ modCount++; if (minCapacity - elementData.length > 0) grow(minCapacity); } /************important**************/ //扩容核心函数,通过创建一个新的大容量数组,然后将旧数组复制到新数组中,改变引用实现 private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } //其中使用到hugeCapacity()函数,是用于处理minCapacity超出MAX_ARRAY_SIZE的情况 private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
7,整体操作
//1,查询ArrayList元素数量 public int size() { return size; } //2,查询是否为空 public boolean isEmpty() return size == 0; } //3,clone public Object clone() //4,toArray转化成一个数组 public Object[] toArray()//Object实现 public <T> T[] toArray(T[] a)//泛型实现
8,数据操作
//0,索引越界检查,被其他函数调用的私有方法,如果越界会抛异常 private void rangeCheck(int index){ if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private void rangeCheckForAdd(int index) //1,查询是否包含某元素 public boolean contains(Object o){ return indexOf(o) >= 0; } //2,查询元素的第一次出现的索引,可以查空元素,不存在的元素返回-1 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; } //3,查询元素的最后一次出现的索引,可以查空元素,不存在的元素返回-1,实现和上一个基本一样,遍历顺序相反而已 public int lastIndexOf(Object o) //4,根据索引查元素 public E get(int index) //5,根据索引设置元素 public E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; } //6,插入到尾,内部要调用扩容函数,这时候可以理解一系列扩容方法的意义,每次可能需要扩容的时候,根据实际元素数量和现有容量比较看是否真的需要扩容,如果需要就执行扩容,如果不需要,保持当前容量。 public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } //7,向指定索引位置插入元素,观察它的实现,是先将原有数组中元素,想后移动一格,(通过复制数组函数实现),然后将带插入元素复制给空出的位置。 public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } //8,删除索引位置元素,和插入元素方法类似,使用数组复制操作移动一格,尾元素清空 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] = null; // clear to let GC do its work return oldValue; } //9,删除第一个指定元素,删除成功返回true,没有这个元素,返回false public boolean remove(Object o) //10,快速删除,不反回bool值,实际上上面的函数是调用快速删除的 private void fastRemove(int index) //11,批量插入,插入集合类 public boolean addAll(Collection<? extends E> c) //12,插入集合类到指定位置 public boolean addAll(int index, Collection<? extends E> c) //13,删除指定范围内元素 protected void removeRange(int fromIndex, int toIndex) //14,删除所有参数中有的元素 public boolean removeAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, false); } //15,删除所有参数中没有的元素 public boolean retainAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, true); } //16,上两个函数都调用了 private boolean batchRemove(Collection<?> c, boolean complement) { final Object[] elementData = this.elementData; int r = 0, w = 0; boolean modified = false; try { for (; r < size; r++) if (c.contains(elementData[r]) == complement) elementData[w++] = elementData[r]; } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } if (w != size) { // clear to let GC do its work for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; size = w; modified = true; } } return modified; }
9,流操作
ObjectInputStream和ObjectOutputStream是针对类对象的输入输出流,配合ArrayList可以组成灵活的操作,ArrayList有两个和他们相关的方法:
//1,将ArrayList中元素些入到输出流中 private void writeObject(java.io.ObjectOutputStream s) //2,将输入流中的元素读到ArrayList中 private void readObject(java.io.ObjectInputStream s) //具体实现暂不深究,在深入研究输入输出流时再学习
10,List转化与ListIterator
//返回从特定位置开始的迭代器ListIterator public ListIterator<E> listIterator(int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: "+index); return new ListItr(index); } //返回从头开始的迭代器ListIter public ListIterator<E> listIterator() { return new ListItr(0); } //返回一个普通迭代器 public Iterator<E> iterator() { return new Itr(); } //Itr和ListItr是Iterator和ListIterator接口的实现类,详情需要学习迭代器相关内容,再做解释。 //子List public List<E> subList(int fromIndex, int toIndex) { //检测参数是否合规 subListRangeCheck(fromIndex, toIndex, size); return new SubList(this, 0, fromIndex, toIndex); }
11,函数式编程相关
在Java1.8中加入了对函数式编程的一些支持,ArrayList也有一些相应方法,需要理解函数相关接口才好理解。暂跳过。
在http://ifeve.com/有很多相关的中文博客
12,sort
跟据Comparator进行排序
public void sort(Comparator<? super E> c) { final int expectedModCount = modCount; Arrays.sort((E[]) elementData, 0, size, c); if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } modCount++; }
总结,通读了一遍ArrayList源码,发现了不少精巧的设计,加深了对容器类的理解。后续要继续努力学习其他源码——2017/1/16
相关文章推荐
- Java集合框架源码分析之ArrayList
- java集合框架02——ArrayList和源码分析
- java集合框架03——ArrayList和源码分析
- java集合框架03——ArrayList和源码分析
- java集合框架03——ArrayList和源码分析
- Java集合框架之一:ArrayList源码分析
- Java集合框架ArrayList源码分析(一)
- java集合框架03——ArrayList和源码分析
- java集合框架之ArrayList源码分析——如何扩展容量
- ArrayList源码分析
- JDK源码分析之java.util.ArrayList
- ArrayList 源码分析
- Java集合框架源码分析之LinkedList
- ArrayList源码分析(基于JDK1.6)
- ArrayList源码分析(基于JDK1.6)
- Java Collections Framework之ArrayList源码分析(基于JDK1.6)
- Java concurrent Framework并发容器之CopyOnWriteArrayList(1.6)源码分析
- ArrayList源码分析(基于JDK1.6)
- 集合框架源码分析三(实现类篇ArrayList,LinkedList,HashMap)
- 集合框架源码分析三(实现类篇ArrayList,LinkedList,HashMap)