Java Collection ArrayList
2016-08-28 14:26
106 查看
ArrayList是实现List接口的动态数组.实现了所有的list的操作,可以操作所有的元素,包括null值。除了实现List这个接口,ArrayList还提供方法去操作array的长度.这个特性被用来储存这个list.ArrayList和Vector差不多,除了它不是同步的.
在ArrayList中size, isEmpty, get, set, iterator, 和 listIterator这些操作是常数时间复杂度.add操作运行在常数的时间复杂度就是添加n个元素需要O(n)次数。所有的其它操作也是线性的时间复杂度.这个常量与LinkedList相比是低的。
每一个ArrayList实例都有一个capacity。这个capacity是这个array的长度用来储存这个list当中的元素。当ArrayList中被添加一个元素的时候,如果超过了限制capacity会自动增长的.
注意:这种List的实现不是synchronized的。如果多个线程访问一个ArrayList实现,并且至少其中一个线程改变这个线程的结构.它必须synchronized.(结构修改包含很多操作,比如说:添加或者删除一个或者多个元素,或者resize这个ArrayList中数组的大小.只是set其它一个元素的值不是改变它的结构)。一种典型的方法就是把这个ArrayList包装一下,可以使用Collections.synchronizedList方法来包装ArrayList。这是最好的方法在创建这个对象的时候,这样可以防止操作这个list会出现不同步的情况.
下面我们来分析一下ArrayList中的继承关系与源码:
由上面我们可以看到:
1. ArrayList可以看出它是支持泛型的,它继承自AbstractList,实现了List、RandomAccess、Cloneable、Java.io.Serializable接口.
2. AbstractList提供了List接口的默认实现(个别方法为抽象方法)。
3. List接口定义了列表必须实现的方法。
4. RandomAccess是一个标记接口,接口内没有定义任何内容。
5. 实现了Cloneable接口的类,可以调用Object.clone方法返回该对象的浅拷贝。
6. 通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。序列化接口没有方法或字段,仅用于标识可序列化的语义。
1) add
add,先确认这个方法这个list的capacity,然后再添加这个元素。
2) ensureCapacityInternal
3) ensureExplicitCapacity
4) grow
由上面我们可以看出ArrayList可以帮我们动态的扩容数组.但是如果我们知道我们需要添加数据的个数我们可以通过调用ArrayList的下面构造方法来指定list的储存能力.
这里还是用到了System.arraycopy()来进行元素删除.并且返回这个元素。
fastRemove方法和remove方法差不多,只是fastRemove方法没有返回值.而remove(int index)方法返回被删除的对象。
这里删除ArrayList中的元素,是遍历删除(list允许对象重复).然后调用上面分析的fastRemove方法进行元素删除。
这个方法是遍历ArrayList,返回找到的第一个与这个对象equals的index.如果没有就返回-1.
当然这里并没有分析ArrayList的全部方法。只分析了其中几个比较关键的方法。抛专引玉,大家可以自行去看ArrayList的源码。
在ArrayList中size, isEmpty, get, set, iterator, 和 listIterator这些操作是常数时间复杂度.add操作运行在常数的时间复杂度就是添加n个元素需要O(n)次数。所有的其它操作也是线性的时间复杂度.这个常量与LinkedList相比是低的。
每一个ArrayList实例都有一个capacity。这个capacity是这个array的长度用来储存这个list当中的元素。当ArrayList中被添加一个元素的时候,如果超过了限制capacity会自动增长的.
注意:这种List的实现不是synchronized的。如果多个线程访问一个ArrayList实现,并且至少其中一个线程改变这个线程的结构.它必须synchronized.(结构修改包含很多操作,比如说:添加或者删除一个或者多个元素,或者resize这个ArrayList中数组的大小.只是set其它一个元素的值不是改变它的结构)。一种典型的方法就是把这个ArrayList包装一下,可以使用Collections.synchronizedList方法来包装ArrayList。这是最好的方法在创建这个对象的时候,这样可以防止操作这个list会出现不同步的情况.
List list = Collections.synchronizedList(new ArrayList(...));
下面我们来分析一下ArrayList中的继承关系与源码:
1、类结构
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
由上面我们可以看到:
1. ArrayList可以看出它是支持泛型的,它继承自AbstractList,实现了List、RandomAccess、Cloneable、Java.io.Serializable接口.
2. AbstractList提供了List接口的默认实现(个别方法为抽象方法)。
3. List接口定义了列表必须实现的方法。
4. RandomAccess是一个标记接口,接口内没有定义任何内容。
5. 实现了Cloneable接口的类,可以调用Object.clone方法返回该对象的浅拷贝。
6. 通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。序列化接口没有方法或字段,仅用于标识可序列化的语义。
2、类属性
/** * 默认的初始化capacity. */ private static final int DEFAULT_CAPACITY = 10; /** * 共享的array的空实例用于ArrayList的空实例 */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * 这个array用来存储ArrayList的元素. * ArrayList的capacity是这个array的长度. * elementData == EMPTY_ELEMENTDATA将会暴露给当使用DEFAULT_CAPACITY且第一次添加元素的时候 */ private transient Object[] elementData; /** * 这个ArrayList的长度(包含的元素个数). * * @serial */ private int size; /** ArrayList实例被修改的次数 */ protected transient int modCount = 0;
3、add – 添加元素
上面我们只是粗浅的认识了一下ArrayList的类继承关系与内部属性,下面我们来看看其中的方法.其中最重要的就是add方法.这个方法是把添加的元素追加到list实例的end.下面是内部方法的调用图.先有一个大体的印象.1) add
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
add,先确认这个方法这个list的capacity,然后再添加这个元素。
2) ensureCapacityInternal
private void ensureCapacityInternal(int minCapacity) { // 如果这个数据是空数组就设置list最小的capactity if (elementData == EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } // 确定明显的capacity ensureExplicitCapacity(minCapacity); }
3) ensureExplicitCapacity
private void ensureExplicitCapacity(int minCapacity) { // 修改次数加1 modCount++; // 如果最小的capacity比这个list最大储存长度还大扩容 if (minCapacity - elementData.length > 0) grow(minCapacity); }
4) grow
private void grow(int minCapacity) { // 数组之前的长度 int oldCapacity = elementData.length; // 新长度为之前长度的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // 数组copy elementData = Arrays.copyOf(elementData, newCapacity); }
由上面我们可以看出ArrayList可以帮我们动态的扩容数组.但是如果我们知道我们需要添加数据的个数我们可以通过调用ArrayList的下面构造方法来指定list的储存能力.
public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; }
4、remove(int index) – 以下标删除元素(有返回值)
下面我们再来看一看remove方法.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; }
这里还是用到了System.arraycopy()来进行元素删除.并且返回这个元素。
5、fastRemove – 以下标删除元素(无返回值)
我们可以看到这个方法是私有的.看这个方法,主要是为ArrayList的删除元素做准备.private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved > 0) // 把数组index + 1的元素全部copy到index的位置(相当于删除index位置的元素) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work }
fastRemove方法和remove方法差不多,只是fastRemove方法没有返回值.而remove(int index)方法返回被删除的对象。
6、remove(Object o) – 删除list中的对象
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; }
这里删除ArrayList中的元素,是遍历删除(list允许对象重复).然后调用上面分析的fastRemove方法进行元素删除。
7、indexOf(Object) – 查看对象在list第一次出现的位置
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; }
这个方法是遍历ArrayList,返回找到的第一个与这个对象equals的index.如果没有就返回-1.
当然这里并没有分析ArrayList的全部方法。只分析了其中几个比较关键的方法。抛专引玉,大家可以自行去看ArrayList的源码。
相关文章推荐
- Java.集合类.Collection.ArrayList.Iterator
- java 将数组排序 指这种数组:[] ArrayList之类的请用Collection.sort
- 【转】java 容器类使用 Collection,Map,HashMap,hashTable,TreeMap,List,Vector,ArrayList的区别
- java中Collection/Collections;List/Set/Map;ArrayList/Vector/LinkedList;HashSet/HashMap/TreeSet/TreeMap
- 05Java语法回顾_collection之arraylist
- java ArrayList 转成Flex ArrayCollection
- JAVA之旅(十八)——基本数据类型的对象包装类,集合框架,数据结构,Collection,ArrayList,迭代器Iterator,List的使用
- java 容器类使用 Collection,Map,HashMap,hashTable,TreeMap,List,Vector,ArrayList的区别
- Lesson_for_java_day13--java中的集合——Collection、List、ArrayList、LinkedList、Set、HashSet、TreeSet
- 迭代器模式和java集合Collection(一)ArrayList
- java容器---Collection{list{LinkedList ,ArrayList,Vector},Set}
- Java ArrayList Collection.sort排序示例
- Java:集合,Array、Collection(List/Set/Queue)、Map的遍历,比如:ArrayList,LinkedList,HashSet,HashMap
- 【java编程】Collection类之ArrayList去除自定义对象的重复元素
- Java中的ArrayList 、List、LinkedList、Collection关系详解
- Java.Collection.Set.List.Collection.ArrayList
- java 容器类使用 Collection,Map,HashMap,hashTable,TreeMap,List,Vector,ArrayList的区别
- java中的ArrayList 、List、LinkedList、Collection关系详解
- Java核心API -- 6(Collection集合List、Set、ArrayList、HashSet)
- Java Collection Framework 之 ArrayList 源码解析