List
- List 是一个接口,它继承于Collection的接口。
- ArrayList, LinkedList, Vector, Stack是List的4个实现类。
- 如果涉及到“栈”、“队列”、“链表”等操作,应该考虑用List。
- 有序集合,可以通过下标访问集合中的元素。
- 允许重复值,允许有多个null值。
List子类
ArrayList
- ArrayList底层实现是数组结构,是一个大小可变的数组,可以通过下标来访问。线程不安全。
继承AbstractList,实现List接口,提供了相关的添加、删除、修改、遍历等功能。
实现了RandmoAccess接口,提供了随机访问功能。
实现了Cloneable接口,可以使用clone方法,能被克隆。
实现java.io.Serializable接口,则ArrayList支持序列化,能通过序列化去传输。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
- 构造与扩容
通过无参构造,初始化时数组大小为空。
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;
}
当添加第一个元素时,调用ensureCapacityInternal方法判断数组是否为空数组,如果为空,将开辟默认大小DEFAULT_CAPACITY = 10;否则调用ensureExplicitCapacity方法,在此方法中,如果空间不够,将进行扩容,调用grow方法,以1.5倍方式进行扩容。
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity); //101
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
101 - 100
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
3.遍历
三种方式:foreach遍历;循环遍历;迭代器遍历
//foreach遍历
for (Object a:list1){
System.out.print(a+" ");
}
//循环遍历
for (int i=0;i<list1.size();i++){
System.out.print(list1.get(i)+" ");
}
//迭代器遍历
Iterator<Character> iterator = list1.iterator();
while (iterator.hasNext()){
Character next = iterator.next();
System.out.print(next+" ");
}
//ListIterator迭代器遍历 从后往前
ListIterator iterator1 = list1.listIterator();
while (iterator1.hasNext()){
System.out.print(iterator1.next()+" ");
}
//从后往前
ListIterator iterator2 = list1.listIterator(4);
while (iterator2.hasPrevious()){
System.out.print(iterator2.previous()+" ");
}
LinkedList
- LinkedList是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。是非同步的,即线程不安全的。
实现 List 接口,能对它进行队列操作。
实现 Deque 接口,即能将LinkedList当作双端队列使用。
实现了Cloneable接口,可以使用clone方法,能被克隆。
实现java.io.Serializable接口,则LinkedList支持序列化,能通过序列化去传输。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
- 构造与扩容
LinkedList 是一个双向链表,没有初始化大小,也没有扩容的机制。
LinkedList 包含一个非常重要的内部类:Node。Node是双向链表节点所对应的数据结构,它包括的属性有:当前节点所包含的值,前驱和后继。
(2) 从LinkedList的实现方式中可以发现,它不存在LinkedList容量不足的问题。
private static class Node<E> {
E item;//value
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
Vector
- Vector底层是数组。
继承于AbstractList,实现了List, RandomAccess, Cloneable这些接口。
继承了AbstractList,实现了List;所以,它是一个队列,支持相关的添加、删除、修改、遍历等功能。
实现了RandmoAccess接口,即提供了随机访问功能。
实现了Cloneable接口,即实现clone()函数,能被克隆。
和ArrayList不同,Vector中的操作是线程安全的。
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
- 构造与扩容
无参构造函数vector会初始化一个大小为10的空数组。
随着Vector中元素的增加,Vector的容量也会动态增长,默认情况下Vector2倍扩容。capacityIncrement是与容量增长相关的增长系数。capacityIncrement可看作增长因子。如果增长因子大于0,扩大增长因子个的大小。
grow方法:如果capacityIncrement不大于0,Vector是2倍扩容;如果大于0,Vector容量扩大capacityIncrement个。
Stack
1.Stack是栈。它的特性是:先进后出。
是继承于Vector的,由于Vector是通过数组实现的,Vector拥有的属性和功能,Stack都拥有。也说明Stack也是通过数组实现的,而非链表。
但是也可以将LinkedList当作栈来使用。
public class Stack<E> extends Vector<E>
2.构造与方法
Stack只有一个默认构造函数。
/**
* Creates an empty Stack.
*/
public Stack() {
}
执行push时,是通过将元素追加的数组的末尾中。
执行peek时,取出栈顶元素,不执行删除,即返回数组末尾的元素。
执行pop时,取出栈顶元素,并将该元素从栈中删除。
迭代器iterator()
- 迭代器:集合迭代(集合遍历)的工具。所有常用集合都具备了可迭代功能iterator方法,是最为通用的集合迭代方法。
- 迭代器模式:提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。
- 迭代器模式就是用迭代器来承担集合遍历的职责。 为遍历不同集合结构提供统一的接口。
- 只有三个方法:
boolean hasNext() 判断集合中是否有下一个元素
E next()获取集合中下一个元素
void remove();一出元素
//例:
Iterator<Integer> iterator = stack.iterator(); //栈Stack的遍历
while (iterator.hasNext()) {
Integer next = iterator.next();
System.out.print(next + " ");
}
比较与选择
- Vector与ArrayList:
相同:底层和方法的使用是没有区别。
初始化时间:ArrayList在添加第一个元素时初始化,Vector是在构造函数时。
扩容方式:Vector更合理。
线程安全:vector中所有方法都添加了synchronized锁,所有Vector是线程安全的。ArrayList是线程不安全的。 - ArrayList与LinkedList:
底层结构:ArrayList是数组,LinkedList是双向链表。
添加删除:ArrayList随机的添加删除时会造成数据的移动,导致效率过低。LinkedList更适合于随机添加删除方法比较频繁的操作,不会有数据的移动。
随机访问:ArrayList比LinkedList的效率更高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。ArrayList适合随机访问操作比较频繁的。 - 线程安全情况下
多线程条件下需要考虑线程安全问题选择Vector,不需要考虑线程安全则考虑ArrayList。因为加锁操作非常耗时。