今天的博客主题
基础篇 --》常用类 --》Java集合类(一)List
上一篇讲解了最顶级的集合类Conllection。
说是集合类不要认为是一个类,只不过是一个总称而已,他其实是一个接口,别混淆了。
List
public interface List<E> extends Collection<E> {}
List也是一个接口,继承了Conllection。是Conllection的一个子接口。
List接口大概的一个结构体系是这样子的
通过源码注释所得: list是一个有序,可重复的集合。
LIst只是一个接口,都是需要子类来实现的,没什么好讲的。具体看子类实现吧
AbstractList
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {}
Collection集合里的一个抽象类,继承了AbstractCollection抽象类,实现类List接口。
是List接口的一个子类。ArrayList的父类。
虽然是个抽象类,但却只有一个抽象方法。
平时根本用不到,只是内部使用的一个类。等以后有时间出文章通过源码去分析这个类的作用。
ArrayList
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{}
ArrayList继承了AbstractList类,实现了List、RandomAccess、Cloneable、和序列化接口。
ArrayList是List接口的一个实现类。
ArrayList是我们使用最多的一个List集合。
底层数据结构是一个数组队列,相当于动态数组。
特点:
- 容量不固定。(有最大值就是int最大值减8)
- 按照插入顺序来保存元素,可以利用下标来查找值。
- 按照下标访问元素最快。
- 支持元素可以为null。
- 占用空间小。(对比 LinkedList,不占用额外空间来维护链表结构)
- 可以随机访问。
缺点:
- 线程不安全。
- 在中间插入元素慢。
- 删除元素慢。
核心方法(常用API)
public static void main(String[] args) {
// ===核心方法 add(), addAll()
// 声明一个空的集合
List list = new ArrayList();
// 往集合添加一个元素
list.add(0);
// 往集合指定位置添加一个元素
list.add(0,1);
System.out.println(list); // [1, 0]
List list1 = new ArrayList();
list1.add("2");
// 往集合里添加一个集合
list.addAll(list1);
System.out.println(list); // [1, 0, 2]
List list2 = new ArrayList();
list2.add("3");
// 往集合指定位置添加一个集合
list.addAll(0,list2);
System.out.println(list); // [3, 1, 0, 2]
// 这里注意一下,当指定了集合的泛型之后,只能同类型对象的集合使用addAll(),否则在编译时期就会报错
List<String> listStr = new ArrayList();
ArrayList<String> listStr1 = new ArrayList();
List<Integer> listInt = new ArrayList();
ArrayList<Integer> listInt1 = new ArrayList();
listStr.addAll(listInt); // ×
listStr.addAll(listStr1); // √
// ===核心方法 size()
// 获取集合的长度
int size = list.size();
System.out.println(size); // 4
// ===核心方法 isEmpty()
// 判断集合是否为空
boolean empty = list.isEmpty();
System.out.println(empty); // false
List list3 = new ArrayList();
boolean empty1 = list3.isEmpty();
System.out.println(empty1); // true
// ===核心方法 contains()
// 判断集合是否包含某个元素(对数据类型有要求)
boolean contains = list.contains(0);
System.out.println(contains); // false
boolean contains1 = list.contains("0");
System.out.println(contains1); // true
// ===核心方法 get()
// 获取指定位置的元素
Object o = list.get(0);
System.out.println(o.toString()); // 3
// ===核心方法 remove() removeAll() retainAll()
// 移除指定位置的元素
list.remove(3);
System.out.println(list); // [3, 1, 0]
// 移除指定的元素
list.remove("3");
System.out.println(list); // [1, 0]
list.add(2);
list.add(3);
list.add(4);
list.add(5);
System.out.println(list);
List list4 = new ArrayList(); // [1, 0, 2, 3, 4, 5]
list4.add(3);
list4.add(5);
// 移除指定集合里的所有元素
list.removeAll(list4);
System.out.println(list); // [1, 0, 2, 4]
List list5 = new ArrayList();
list5.add(1);
list5.add(2);
// 移除集合里除了指定集合外的所有元素
list.retainAll(list5);
System.out.println(list); // [1, 2]
// ===核心方法 subList()
list.add(3);
list.add(2);
list.add(5);
list.add(4);
System.out.println(list); // [1, 2, 3, 2, 5, 4]
// 截取集合里指定位置的元素
List list6 = list.subList(2, 4);
System.out.println(list6); // [3, 2]
// === 核心方法 sort() 这个方法用的比较少,没这样写过。
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
int i = o1 > o2 ? 1 : -1;
return i;
}
});
System.out.println(list); // [1, 2, 2, 3, 4, 5]
// 替代方法。一般对集合排序都会用父类的这个排序算法
Collections.sort(list);
System.out.println(list); // [1, 2, 2, 3, 4, 5]
// ===核心方法 clear()
// 清空集合里的所有元素
list.clear();
System.out.println(list); // []
}
LinkedList
public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable{}
LinkedList继承了AbstractSequentialList类。实现了List、Deque、Cloneable和Serializable接口。
LinkedList也是List接口的一个实现类。
LinkedList底层数据结构是通过双向链表去实现的。
特点:
- 容量大,因为是链表,不会出现容量不足的问题
- 可以作为栈、队列、双端队列数据结构使用。
- 在插入和删除元素是效率高。
缺点:
- 同样线程是不安全的。
- 随机访问速度慢。
核心方法(常用API)
public static void main(String[] args) {
// 声明一个LinkedList集合
LinkedList list = new LinkedList();
// ===添加方法
// 往集合内添加一个元素。在链表后添加一个元素
list.add("1");
System.out.println(list); // [1]
// 往集合前头添加一个元素。在链表的最前增加一个元素
list.addFirst("2");
System.out.println(list); // [2, 1]
// 往集合尾部添加一个元素。在链表的最后增加一个元素
list.addLast("3");
System.out.println(list); // [2, 1, 3]
// 往集合指定位置添加一个元素
list.add(2,"4");
System.out.println(list); // [2, 1, 4, 3]
// 和addFirst方法一样
list.push("5");
System.out.println(list); // [5, 2, 1, 4, 3]
// 和addLast方法一样
list.offer("6");
System.out.println(list); // [5, 2, 1, 4, 3, 6]
// JDK1.6版本之后才有的方法。和addFirst方法一样
list.offerFirst("7");
System.out.println(list); // [7, 5, 2, 1, 4, 3, 6]
// JDK1.6版本之后才有的方法。和addLast方法一样
list.offerLast("8");
System.out.println(list); // [7, 5, 2, 1, 4, 3, 6, 8]
// ===删除方法
// 删除链表里的第一个元素
list.remove();
System.out.println(list); // [5, 2, 1, 4, 3, 6, 8]
// 删除链表指定位置的元素
list.remove(3);
System.out.println(list); // [5, 2, 1, 3, 6, 8]
// 删除链表指定的元素
list.remove("8");
System.out.println(list); // [5, 2, 1, 3, 6]
// 删除链表头部元素,并返回
list.removeFirst();
System.out.println(list); // [2, 1, 3, 6]
// 删除链表尾部元素,并返回
list.removeLast();
System.out.println(list); // [2, 1, 3]
// 查询并删除链表第一个元素
list.poll();
System.out.println(list); // [1, 3]
// 和removeFirst方法一样
list.pop();
System.out.println(list); // [3]
list.add("2");
list.add("1");
list.add("4");
list.add("5");
list.add("6");
System.out.println(list); // [3, 2, 1, 4, 5, 6]
// === 查询方法
// 获取指定位置的元素
Object o = list.get(3);
System.out.println(o); // 4
// 获取链表第一个元素
Object first = list.getFirst();
System.out.println(first); // 3
// 获取链表最后一个元素
Object last = list.getLast();
System.out.println(last); // 6
// 获取链表第一个元素,但不删除
Object peek = list.peek();
System.out.println(peek); // 3
// 和peek方法一样
Object peekFirst = list.peekFirst();
System.out.println(peekFirst); // 3
// 获取链表最后一个元素,但不删除
Object peekLast = list.peekLast();
System.out.println(peekLast); // 6
// 获取链表长度
int size = list.size();
System.out.println(size); // 6
}
Vector(矢量队列)
public class Vector<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{}
继承了AbstractList抽象类,实现了List、RandomAccess、Cloneable和Serializable接口
我们发现Vector实现类的体系结构和ArrayList是一样的。
Vector类实现了一个动态数组。和 ArrayList 很相似,
但不同的是:Vector是同步访问的也就是说线程是安全的。Vector里面包含了许多传统方法,不属于集合里
特点:
- 和ArrayList底层数据结构一样并且类实现也一样,其优点也一样 随机访问速度快,插入和移除性能较差 (这是数组的特点)
- 重要一点就是线程安全
缺点:
- 线程安全了,效率自然而然就低了
核心方法(常用API)
public static void main(String[] args) {
// 声明一个Vector(矢量队列)集合
Vector vector = new Vector();
// 将指定的元素追加到此向量的末尾
vector.add("1");
vector.add("2");
System.out.println(vector); // [1, 2]
// 在此向量的指定位置增加指定的元素
vector.add(1,"3");
System.out.println(vector);
// 将指定的集合添加到此向量的末尾
List list = new ArrayList();
list.add("4");
vector.addAll(list);
System.out.println(vector); // [1, 3, 2, 4]
// 在此向量的指定位置增加指定的集合
List list1 = new ArrayList();
list1.add("5");
vector.addAll(0,list1);
System.out.println(vector); // [5, 1, 3, 2, 4]
// 获取此向量的长度
int size = vector.size();
System.out.println(size); // 5
// 返回此向量的当前容量,一般用不到
int capacity = vector.capacity();
System.out.println(capacity); // 10
// 获取此向量指定位置的元素
Object o = vector.get(3);
System.out.println(o); // 2
// 移除此向量里指定的元素
vector.remove("5");
System.out.println(vector); // [1, 3, 2, 4]
// 移除此向量指定位置的元素
vector.remove(2);
System.out.println(vector); // [1, 3, 4]
// 移除此向量里指定集合里的元素
List list2 = new ArrayList();
list2.add("3");
vector.removeAll(list2);
System.out.println(vector); // [1, 4]
// 判断此向量是不是空的
boolean empty = vector.isEmpty();
System.out.println(empty); // false
// 判断此向量是否包含指定的元素
boolean contains = vector.contains("1");
System.out.println(contains); // true
// 此向量是否包含指定元素,包含返回对应下标,不包含返回-1
int i = vector.indexOf("1");
int i2 = vector.indexOf("11");
System.out.println(i); // 0
System.out.println(i2); // -1
// 清空此向量里的所有元素
vector.clear();
System.out.println(vector); // []
}
Stack
public class Stack<E> extends Vector<E> {}
Stack继承了Vector,是Vector的子类。
Stack比较简单,继承了Vector。
Stack翻译过来是栈的意思,特性就是:先进后出(FILO Frist In Last Out)
特点就不用说了吧,是Vector的子类,那么父类有啥子类都会有啥的。
而Stack里面的方法也不是很多,除了一个构造函数之外只有5个方法。
public static void main(String[] args) {
// 声明一个Stack(栈)集合
Stack stack = new Stack();
// 将指定元素推送到栈顶部
stack.push("1");
stack.push("2");
stack.push("3");
System.out.println(stack); // [1, 2, 3]
// 获取栈顶部元素,但不会移除这个元素
Object peek = stack.peek();
System.out.println(peek); // 3
// 移除栈顶部元素,并返回这个被移除的元素
Object pop = stack.pop();
System.out.println(pop); // 3
System.out.println(stack); // [1, 2]
// 栈是否为空
boolean empty = stack.empty();
System.out.println(empty); // false
// 获取指定元素出现在栈上的位置
int search = stack.search("2");
System.out.println(search); // 1
}
总结
List是一个接口,继承Collection接口,是一个有序可重复的集合。
AbstractList是一个抽象类,继承AbstractCollection,实现List接口。
AbstractSequentialList是一个抽象类,继承AbstractList。
ArrayList底层数据结构实现是数组队列,相当于动态数组。由于是数组实现,所以随机访问效率高,插入/删除效率低。是List接口的一个实现类
LinkedList底层数据结构是双向链表。它也可以被当作堆栈、队列或双端队列进行操作。因为是链表实现,所以随机访问效率低,插入/删除效率高。
Vector是矢量队列,底层数据结构也是数组,和ArrayList一样。但ArrayList线程是不安全的,而Vector线程是安全的。
Stack是栈,继承Vector。它的特性就是:先进后出(FILO)
简单总结
- ArrayList底层数据结构是数组,查询快,增删慢。线程不安全,效率高。(比较常用)
- LinkedList底层数据结构式链表,查询慢,增删快。线程不安全,效率高。
- Vector底层数据结构是数组,查询快,增删慢。线程安全,效率低。
场景
学习的东西始终都是要来应用的,如果不用学了岂不是白学了。
那学完这篇集合之后,在Java当中我们在那些地方应用它呢?这么多实现类用的时候怎么选择呢?
再用的时候我们需要根据需求来抉择,
需要安全吗?如果要安全那就选择Vector(但是即使要用这个还是不要选择,后面分析)
查询的多就用ArrayList,增删多就用LinkedList。
一般在开发中信手捏来的就是ArrayList,还是这个比较用的多一点。
这些就是List集合里面一些常用的。我们先熟悉认识这些,等后边源码篇的时候会着重分析集合这些,这部分还是比较重要的。
坚持!!!