Java 集合之ArrayList
List 接口的可调整大小的数组实现。 实现所有可选的列表操作,并允许包括 null
在内的所有元素。 除了实现 List 接口之外,该类还提供了操作内部用于存储列表的数组大小的方法。 (这个类大致相当于 Vector,只是它是不同步的。)
size
、isEmpty
、get
、set
、iterator
和 listIterator
操作在恒定时间内运行。 add 操作以分摊的固定时间 运行,即添加 n 个元素需要 O(n) 时间。 所有其他操作都在线性时间内运行(大体上讲)。 与 LinkedList 实现相比,常量因子较低。
每个 ArrayList 实例都有一个容量capacity。 容量是用于存储列表中元素的数组的大小。 它始终至少与列表大小一样大。 随着元素被添加到 ArrayList,它的容量会自动增长。并未指定增长策略的细节,因为这不只是添加元素会带来分摊固定时间开销那样简单。JDK1.7底层数组在调用构造器时,数组初始化长度为10,扩容的时候拓展为原来的1.5倍;JDK1.8在调用构造器时,底层数组为{}
,在调用add
方法后才重新赋值为长度为10的新数组,节省了内存
// 用于默认大小的空实例的共享空数组实例。 我们将其与 EMPTY_ELEMENTDATA 区分开来,以了解添加第一个元素时要膨胀多少。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
};
private static final int DEFAULT_CAPACITY = 10;
/**
* ArrayList 的元素存储在其中的数组缓冲区。
* ArrayList 的容量就是这个数组缓冲区的长度。
* 添加第一个元素时,任何带有 elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的空 ArrayList 都将扩展为 DEFAULT_CAPACITY。
*/
transient Object[] elementData; // 底层的Object类型数组,非私有以简化嵌套类访问
private int size; //ArrayList 的大小(有效长度,它包含的元素数)。
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
add
时才会扩容
public boolean add(E e) {
//添加元素
ensureCapacityInternal(size + 1); //当数组中的位置都满了就开始进行扩容,扩容长度为原数组的1.5倍。增量modCount ! !
elementData[size++] = e; //size自动+1
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
扩容相关代码
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 有溢出意识的代码
if (minCapacity - elementData.length > 0)
grow(minCapacity); //扩容
}
private void grow(int minCapacity) {
// 有溢出意识的代码
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //扩容1.5倍
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity 通常接近 size,所以这是一个win:
elementData = Arrays.copyOf(elementData, newCapacity); //扩容本质,将elementData指向由原数组指向新数组
}
在添加大量元素前,应用程序可以使用 ensureCapacity
操作来增加ArrayList实例的容量。 这可以减少递增式再分配的数量。
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY; // 如果elementData不为空,则minExpand赋值为0,否则赋值为10
//elementData为空时,如果minCapacity>10就扩容,elementData不为空时,无路如何都会扩容
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
请注意,此实现不是同步的。 如果多个线程同时访问一个 ArrayList 实例,并且至少有一个线程在结构上修改了列表,则必须在外部进行同步。 (结构上的修改是指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小;仅设置元素的值不是结构修改。)
这一般通过对自然封装该列表的对象进行同步操作来完成。 如果不存在此类对象,则应使用 Collections.synchronizedList 方法“包装”该列表。 这最好在创建时完成,以防止对列表的意外不同步访问: List list = Collections.synchronizedList(new ArrayList(...));
此类的 iterator 和 listIterator 方法返回的迭代器是快速失败fail-fast的:在创建迭代器之后,除非通过迭代器自身的 remove
或 add
方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器将抛出 ConcurrentModificationException。 因此,面对并发修改,迭代器很快就会完全失败,而不是冒着在未来不确定的时间出现任意、非确定性行为的风险。
请注意,无法保证迭代器的快速失败行为,因为一般而言,在存在非同步并发修改的情况下不可能做出任何硬性保证。 快速失败的迭代器会尽最大努力抛出 ConcurrentModificationException。 因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测 bug。
ArrayList与Vector:底层都是数组的扩容,但Arraylist底层扩容为原数组1.5倍,线程不安全,效率高;Vector底层扩容为原数组的2倍,线程安全,效率低,已淘汰。
构造器
ArrayList()
- 构造一个初始容量为 10 的空列表。
ArrayList(int initialCapacity)
- 构造一个具有指定初始容量的空列表。
ArrayList(Collection<? extends E> c)
- 构造一个包含指定 collection 元素的列表,按照集合迭代器返回的顺序排列。
方法
Modifier and Type | Method | Description |
---|---|---|
boolean | add(E e) | 将指定的元素添加到此列表的尾部。 |
void | add(int index, E element) | 将指定的元素插入此列表中的指定位置。 |
boolean | addAll(Collection<? extends E> c) | 按照指定 collection 的迭代器所返回的元素顺序,将该 collection 中的所有元素添加到此列表的尾部。 |
boolean | addAll(int index, Collection<? extends E> c) | 从指定的位置开始,将指定 collection 中的所有元素插入到此列表中。 |
void | clear() | 移除此列表中的所有元素。 |
Object | clone() | 返回此 ArrayList 实例的浅表副本。 |
boolean | contains(Object o) | 如果此列表中包含指定的元素,则返回 true。 |
void | ensureCapacity(int minCapacity) | 如有必要,增加此 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数。 |
boolean | equals (Object o) | 比较指定的对象和这个列表是否相等。 |
void | forEach (Consumer<? super E> action) | 对 Iterable 的每个元素执行给定的动作,直到所有元素都被处理或动作抛出异常。 |
E | get(int index) | 返回此列表中指定位置上的元素。 |
int | hashCode() | 返回此列表的哈希码值。 |
int | indexOf(Object o) | 返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。 |
boolean | isEmpty() | 如果此列表中没有元素,则返回 true |
Iterator | iterator() | 以适当的顺序返回此列表中元素的迭代器。 |
int | lastIndexOf (Object o) | 返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回 -1。 |
ListIterator | listIterator() | 返回此列表中元素的列表迭代器(以适当的顺序)。 |
ListIterator | listIterator (int index) | 返回列表中元素的列表迭代器(以适当的顺序),从列表中的指定位置开始。 |
E | remove(int index) | 移除此列表中指定位置上的元素。 |
boolean | remove(Object o) | 移除此列表中首次出现的指定元素(如果存在)。 |
boolean | removeAll (Collection<?> c) | 从此列表中删除包含在指定集合中的所有元素。 |
boolean | removeIf (Predicate<? super E> filter) | 移除此集合中满足给定谓词的所有元素。 |
protected void | removeRange(int fromIndex, int toIndex) | 移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素。 |
boolean | retainAll (Collection<?> c) | 仅保留此列表中包含在指定集合中的元素。 |
E | set(int index, E element) | 用指定的元素替代此列表中指定位置上的元素。 |
int | size() | 返回此列表中的元素数。 |
Spliterator | spliterator() | 在此列表中的元素上创建一个后期绑定和快速失败的 Spliterator。 |
List | subList (int fromIndex, int toIndex) | 返回此列表中指定的 fromIndex(包括)和 toIndex(不包括在内)之间的部分的视图。 |
Object[] | toArray() | 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组。 |
T[] | toArray(T[] a) | 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。 |
void | trimToSize() | 将此 ArrayList 实例的容量调整为列表的当前大小。 |
- 从类 java.util.AbstractList继承的方法
equals, hashCode
- 从类 java.util.AbstractCollection继承的方法
containsAll, toString
- 从类 java.lang.Object继承的方法
finalize, getClass, notify, notifyAll, wait, wait, wait
- 从接口java.util.Collection继承的方法
parallelStream, stream, toArray
- 从接口java.util.List继承的方法
containsAll, replaceAll, sort
ArrayList alist = new ArrayList(4);
alist.add(2);
alist.add(9.2);
alist.add(true);
alist.add("abc");
System.out.println("集合中元素的数量为:"+alist.size()); //4
System.out.println("集合是否为空:"+alist.isEmpty()); //false
System.out.println("是否包含元素:"+alist.contains(3)); //false
System.out.println(alist); //[2, 9.2, true, abc]
alist.add(1,66);
System.out.println(alist); //[2, 66, 9.2, true, abc]
alist.set(1,6);
System.out.println(alist); //[2, 6, 9.2, true, abc]
alist.remove(2);//在集合中存入的是Integer类型数据的时候,调用remove方法调用的是:remove(int index)
System.out.println(alist); //[2, 6, true, abc]
alist.remove("abc");
System.out.println(alist); //[2, 6, true]
Object o = alist.get(0);
System.out.println(o); // 2
遍历方法
//方式1:普通for循环:
System.out.println("-------普通for循环-------");
for(int i = 0;i<alist.size();i++){
System.out.print(alist.get(i) + "\t");
}
//方式2:增强for循环:
System.out.println("\n-------增强for循环-------");
for(Object obj:alist){
System.out.print(obj + "\t");
}
//方式3:迭代器:
System.out.println("\n-------迭代器-------");
Iterator it = alist.iterator();
while(it.hasNext()){
System.out.print(it.next() + "\t");
}