前言
集合是我们在开发中经常会使用的工具,不同的集合实现类有着不同的特性,而很多开发者却一个ArrayList从头用到尾,这种做法是非常不可取的,所以我决定写一篇博客全面记录集合的各个实现类已经用法
一、概述
以下是集合的框架图
由上图可知,我们的集合的顶层接口是Iterable被Collectionb继承,而List,Queue,Set则是Collection接口的三个最主要的子接口。
二、Iterable
Iterable是一个迭代器接口,它的作用是方便我们对集合进行遍历
源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
可以看出来,Iterable支持lambda函数接口,还需要注意的是它的forEach方法,我们可以看到它的参数是个Consumer类型的,所以在forEach内部我们常常用lambda特性来创建匿名接口实现对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
由上面的代码可以看出,Iterator对象两个最常用的方法是hasNext()和next(),一个是用来判断容器中是否还有元素,一个是返回当前元素的下一个元素
三、Collection
该接口的源码就不给大家展示了,我们只需要知道该接口声明的常用方法即可
1. 增
boolean add(E e);
boolean addAll(Collection<? extends E> c);
2. 删
boolean remove(Object o);
boolean removeAll(Collection<?> c);
default boolean removeIf(Predicate<? super E> filter)
3. 子集
boolean contains(Object o);
boolean containsAll(Collection<?> c);
4. 交集
boolean retainAll(Collection<?> c);
5. 转成数组
<t> T[] toArray(T[] a);
Object[] toArray();
这两种toArray方法的返回类型是不一样的!!!</t>
6. 其它常用api
void clear();
int size();
boolean isEmpty();
四、ArrayList
ArrayList是List接口的实现类,它的特点是有序,所以它能通过索引来进行增删改查。
- 增:add(E e) addAll(Collection<? extends E> c);
- 删:remove(int index) remove(E obj) removeAll(Collection col);
- 改:set(int index, E e);
- 查:get(int index);
- 插:add(int index, E e) addAll(int index, Collection<? extends E> c);
- 长度:size();
ArrayList最大的特点就是会自动扩充,那它扩充的机制到底是怎样的呢?我们来分析源码
ArrayList基本属性和构造方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
|
ArrayList添加元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
ArrayList扩容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
五、LinkedList
LinkedList是一个非常强大的实现类,它既实现了List的接口,又实现了DeQue(双端队列)的接口。
LinkedList结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
可以看出LinkedList有一个头指针first和一个尾指针last,也就是我们数据结构里面的双端队列的逻辑结构。在Java中,传统的队列Queue 添加元素是在队尾添加,删除或取出元素是在队头进行操作,而LinkedList作为双端队列既可以在队头进行添加或删除,也可以在队尾进行添加和删除
Node的结构(LinkedList内部类)
1 2 3 4 5 6 7 8 9 10 11 |
|
可以看出Node对象具有next和prev两个指针,一个指向前,一个指向后,所以由Node结点组成的LinkedList不但是一个双端队列,还是个双链表
常用api
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
以上是LinkedList作为DeQue实现类具有的api,除此之外LinkedList还实现了List接口中的方法,具体可以参考上面的ArrayList常用api,在此不再赘述
六、总结
在上面我们主要谈到了Iterator、Collection、以及List的两个实现类ArrayList和LinkedList,下面我们就来总结一下它们各自的功能以及特点吧
1. Iterator:迭代器对象,用来遍历集合,next()用来得到下一个元素,hasNext()判断集合是否遍历结束。
注意点:一个Iterator对象只能遍历一遍,若要遍历第二遍则需要重新创建该集合的Iterator
2. List:一个有序的集合接口,它可以通过索引来进行插入,删除,访问
3. ArrayList:它是List的实现类,开发中我们通常使用它来代替数组,需要注意的是它的底层是Object数组,默认大小是10,当添加元素的时候会判断它的容量是否够用,若不够的话则扩容为1.5倍大小,若还不够,则将其扩容为需要的大小
4. LinkedList:它实现了List接口和DeQue接口,具有它们两者的特性,除此之外它的结构是一个双端队列,可以从队头/队尾添加、删除、访问元素
ArrayList和LinkedList区别:
它们的区别由它们底层的数据结构所决定,由于ArayList底层是object数组,所以它具有随机访问特性,更适合查询业务比较多的场景,而LinkedList本质上是一个双链表,它更适合插入删除比较多的业务场景。