今天的博客主题
基础篇 --》常用类 --》Java集合类(一)List
上一篇讲解了最顶级的集合类Conllection。
说是集合类不要认为是一个类,只不过是一个总称而已,他其实是一个接口,别混淆了。
List也是一个接口,继承了Conllection。是Conllection的一个子接口。
List接口大概的一个结构体系是这样子的
通过源码注释所得: list是一个有序,可重复的集合。
LIst只是一个接口,都是需要子类来实现的,没什么好讲的。具体看子类实现吧
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {}
Collection集合里的一个抽象类,继承了AbstractCollection抽象类,实现类List接口。
是List接口的一个子类。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,不占用额外空间来维护链表结构)可以随机访问。缺点:
线程不安全。在中间插入元素慢。删除元素慢。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); // [] }
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底层数据结构是通过双向链表去实现的。
特点:
容量大,因为是链表,不会出现容量不足的问题可以作为栈、队列、双端队列数据结构使用。在插入和删除元素是效率高。缺点:
同样线程是不安全的。随机访问速度慢。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 }
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底层数据结构一样并且类实现也一样,其优点也一样 随机访问速度快,插入和移除性能较差 (这是数组的特点)重要一点就是线程安全缺点:
线程安全了,效率自然而然就低了
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集合里面一些常用的。我们先熟悉认识这些,等后边源码篇的时候会着重分析集合这些,这部分还是比较重要的。