List 集合代表一个元素有序、可重复的集合。
集合中每个元素都有其对应的索引,元素的存放顺序和添加顺序一致,从索引 0 开始,依次递增。
List 集合会根据元素的数量自动扩容。
返回目录
List 集合中常用的类有 ArrayList 和 LinkedList;
ArrayList 类底层是数组。
LinkedList 类底层是链表。同时该类也继承了 Deque 接口,代表可以作为双端队列和栈使用(不推荐,推荐使用 ArrayDeque)。
Vector 类和其子类 Stack,不推荐使用。
返回目录
List 接口是 Collection 接口的子接口,可以使用 Collection 接口里的方法。
(需要看 Collection 接口的方法,可以看本人另一篇博客《JavaSE 集合入门》)
而且由于 List 是有序集合,因此 List 集合里增加了一些根据索引来操作元素的方法。
public interface List<E> extends Collection<E> {
...
//将元素 element 插入到指定索引 index 处。
void add(int index, E element);
//将集合 c 插入到指定索引 index 处。
boolean addAll(int index, Collection c);
//返回指定索引处的元素
E get(int index);
//返回对象 o 在集合中第一次出现的位置索引
int indexOf(Object o);
//返回对象 o 在集合中最后一次出现的位置索引
int lastIndexOf(Object o);
//删除并返回指定索引处的元素
E remove(int index);
//替换索引处的元素,并返回旧元素
E set(int index, E element);
//根据传入的比较器,进行排序
default void sort(Comparator c) {...}
...
}
注意1:List 判断两个对象相同是通过 equals() 方法。
public class ArrayList<E> ...{
...
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++)
//通过 equals() 方法判断元素是否相等
if (o.equals(elementData[i]))
return i;
}
return -1;
}
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++)
//通过 equals() 方法判断元素是否相等
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
...
}
返回目录
List<String> list = new ArrayList<>();
list.add("abc");
list.add("ab");
list.add("a");
System.out.println(list); // [abc, ab, a]
list.sort((s1, s2) -> {
return s1.length() - s2.length();
});
System.out.println(list); // [a, ab, abc]
返回目录
该类底层是数组。
该类是线程不安全的。
该类可以添加 null。
返回目录
ArrayList 类底层是一个 Object[] 数组(数组名为:elementData) 。
默认为空数组,可以通过有参构造器,指定数组的初始容量。
public class ArrayList<E> ...{
...
transient Object[] elementData;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//无参构造器,初始化一个空数组
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//有参构造器,初始化一个指定容量(≥0)的数组
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
...
}
返回目录
当使用无参构造器创建 ArrayList 时,初始容量为 0;第一次扩容为 10;以后每次扩容为原来容量的 1.5 倍。
当使用有参构造器创建 ArrayList 时,初始容量自定义(≥0);如果初始容量 ≥ 2,则每次扩容为原来容量的 1.5 倍;
如果初始容量为 0,则与无参构造器的情况相同;如果初始容量为 1,则第一次扩容为 2;以后每次扩容为原来容量的 1.5 倍。
public class ArrayList<E> ...{
...
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
private static final int DEFAULT_CAPACITY = 10;
//1、添加元素
public boolean add(E e) {
//跳转到2
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//2、确保数组容量够用(不明确,需要考虑数组为空数组的情况)
private void ensureCapacityInternal(int minCapacity) {
//跳转到3
//跳转到4
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//3、计算所需容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//如果数组为空,则返回容量为 10
//如果数组不为空,则返回容量为 minCapacity
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//4、确保数组容量够用(明确的)
private void ensureExplicitCapacity(int minCapacity) {
// modCount 记录数组被改变的次数
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
// 跳转到5
grow(minCapacity);
}
//5、执行扩容(扩容为原容量的1.5倍)
private void grow(int minCapacity) {
// overflow-conscious code
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);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
...
}
返回目录
public class ArrayList<E> ...{
...
// 构造器方法
// 无参构造器,初始容量为 0,第一次扩容为 10
public ArrayList() {...}
// 有参构造器,初始容量自定义
public ArrayList(int initialCapacity) {...}
// 有参构造器,复制集合中的元素
public ArrayList(Collection<? extends E> c) {...}
// 继承 List 接口的方法
// 继承 Collection 接口的方法
...
}
返回目录
该类底层是双向链表。
该类实现了 List 接口,可以根据索引来随机访问集合中的元素(效率低)。
该类同时还实现 Deque 接口,可以被当成双端队列、栈来使用(不推荐)。
该类可以添加 null,元素可以重复。
该类线程不安全。
返回目录
LinkedList 底层是双向链表。
维护着指向头节点的 first 变量,指向尾节点的 last 变量。
节点类型为 Node 类,是 LinkedList 的内部类。
public class LinkedList<E> ...{
...
//指向头节点,初始为Null
transient Node<E> first;
//指向尾节点,初始为Null
transient Node<E> last;
//在链表的末尾添加元素
public boolean add(E e) {
linkLast(e);
return true;
}
//在链表的末尾添加元素
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
// 内部类 Node,作为链表节点的数据类型
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
...
}
返回目录
public class LinkedList<E> ...{
...
//1、作为双端队列
//在队头、队尾添加节点,有返回值
public boolean offerFirst(E e) {...}
public boolean offerLast(E e) {...}
//删除并返回队头、队尾元素
public E pollFirst() {...}
public E pollLast() {...}
//返回队头、队尾元素,但不删除
public E peekFirst() {...}
public E peekLast() {...}
//2、作为栈
//入栈
public void push(E e) {...}
//出栈
public E pop() {...}
//查看栈顶元素
public E peek() {...}
// 继承 List 接口的方法
// 继承 Collection 接口的方法
...
}
返回目录
(1)Vector 是一个古老的集合(从 JDK 1.0 就有了),那时候 Java 还没有提供系统的集合框架,所以 Vector 里提供了一些名字很长的方法。
(2)Vector 是线程安全的,所以性能比 ArrayList 低。
(3)Stack 类继承了 Vector 类,因此它也是一个古老的 Java 集合类。它同样是线程安全、性能较差的。因此应该少用 Stack 类。
返回目录
(1)需要保证 List 集合线程安全时,不推荐使用 Vector 类,建议使用 Collections 类将一个 ArrayList 对象变成线程安全的。
(2)需要使用“栈”时,不推荐使用 Stack 类,可以使用 LinkedList 类和 ArrayDeque 类。推荐使用 ArrayDeque 类。
返回目录
改查操作多,使用 ArrayList。
增删操作多,使用 LinkedList。
不使用 Vector。
返回目录