零、前言
Collection是[收集品]的意思,这里称[容器],是java中的一个接口,位于
java.util
包下
Collection下有三大接口:
List(列表)
、
Set(集合)
、
Queue(队列)
第一节:List接口
List:列表,顾名思义是一种表结构,核心方法:
按索引插入元素
void add(int var1, E var2)
按索引删除元素
E remove(int var1);
按索引修改元素
E set(int var1, E var2)
按索引查询元素
E get(int var1)
特点:
1.增删改查操作都可以按照索引进行精确的控制,所以是元素的有序排列
2.允许相同元素
List是java中使用频率非常高的一个接口,最要的子类:ArrayList、Vector、LinkedList
1.其中ArrayList、Vector是AbstractList-->AbstractCollection-->Collection 路线
2.LinkedList不止实现了List,还实现了Deque,就像得到两个师傅的真传,招式(方法)更多一些
Queue接口是队列(先进先出),Deque接口(双端队列)是Queue的弟子,两头都能随意进出
所以根据需求即可当栈也可当队列,LinkedList得到了Deque的真传,所以也可以
关于抽象类:
抽象类一般是先实现接口,或者拓展一些子类公用方法,总之就是把能做的先做了。
有种天下父母心的感觉,就像AbstractList对ArrayList说:我能帮你做的尽量都做了,接下来就看你的了
public abstract class AbstractCollection<E> implements Collection<E>
public abstract class AbstractSequentialList<E> extends AbstractList<E>
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>
1.ArrayList:数组列表
2.Vector:载体
3.LinkedList:链式列表
4.Vector、ArrayList与 LinkedList的比较
可以说Vector、ArrayList是亲兄弟,LinkedList算个堂兄
项目
|
线程安全?
|
实现
|
扩容
|
定点添加/删除
|
尾添加/删除
|
查询
|
修改
|
ArrayList
|
否
|
数组
|
50%
|
O(n)
|
O(1)
|
O(1)
|
O(1)
|
Vector
|
是
|
数组
|
100%
|
O(n)
|
O(1)
|
O(1)
|
O(1)
|
LinkedList
|
否
|
双链表
|
--
|
O(n)
|
O(1)
|
O(n)
|
O(n)
|
尾添加测试[add(E)]
----
|
复杂度
|
1000
|
10000
|
10W
|
100W
|
1000W
|
ArrayList
|
O(1)
|
0.0004秒
|
0.0016秒
|
0.0063秒
|
0.0297秒
|
0.6704秒
|
LinkedList
|
O(1)
|
0.0004秒
|
0.0017秒
|
0.0098秒
|
0.2384秒
|
2.4285秒
|
操作数opCount=1000W:插入的位置与耗时比较
----
|
1/9
|
3/9
|
5/9
|
7/9
|
8/9
|
ArrayList
|
0.1496秒
|
0.1136秒
|
0.0821秒
|
0.0297秒
|
0.0012秒
|
LinkedList
|
0.0150秒
|
0.0251秒
|
0.0386秒
|
0.0176秒
|
0.0102秒
|
可见ArrayList越往后插入越快,因为要变动的元素越少
LinkedList从两头到中间速度变慢,取决于链表的查询机制,总的来说,
随机添加LinkedList比较有优势些,只是末尾添加ArrayList较好
数组和双链表两种数据结构:
数组:定点添加,后面元素都要往后挪个位,O(n)-------双链表:耗时在找到那个定点,添加很快,综合O(n)
数组:定点删除,后面元素都要往前挪个位,O(n)-------双链表:耗时在找到那个定点,删除很快,综合O(n)
数组:定点查询,数组自带索引光环,O(1) -------双链表:一个一个挨着找 O(n)
数组:定点修改,数组自带索引光环,O(1) -------双链表:耗时在找到那个定点,修改很快,综合O(n)
综上所属:
随机访问、修改性能:Vector、ArrayList>LinkedList
考虑到Vector、ArrayList添加或删除时:
1.可能伴随扩容/缩容,
2.当元素个数巨大时,可能造成大量空闲空间
3.数组连续开辟空间,会造成储存空间的碎片化
的这些问题,在大量添加或删除操作使用LinkedList是更好的选择
因为双链表:
1.双链表的添加/删除耗时在查找工作,而双链表查询时会查看索引在前半还是后半
来决定从头查询或从尾查询,从而最差情况只需size/2,而数组最差情况为size
2.链表不需要开辟连续空间,从而避免储存空间的碎片化
另外在数据非常巨大的时候:
LinkedList基于双链表,需要new 巨大数量的节点(Node),
Vector、ArrayList只是开辟空间,所以更好一些,所以根据需求酌情处理
关于 Vector
Vector类对集合的元素操作时都加了synchronized,保证线程安全。但使得效率下降:如
public synchronized boolean add(E e) {
modCount++;
add(e, elementData, elementCount);
return true;
}
所谓同步:即当一个Iterator被正在被使用,另一个线程对Vector添加或删除元素,这时调用Iterator的方法时将抛出异常
public synchronized void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final int expectedModCount = modCount;
final Object[] es = elementData;
final int size = elementCount;
for (int i = 0; modCount == expectedModCount && i < size; i++)
es[i] = operator.apply(elementAt(es, i));
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
modCount++;
}
可以看到很多关于修改的方法当:modCount != expectedModCount时都会扔一个ConcurrentModificationException异常
也就是期望的修改次数与真实的修改次数不一致时
第二节:Set接口
集合:数学上的集合性质:
确定性:给定一个集合,任给一个元素,该元素或者属于或者不属于该集合
互异性:一个集合中,任何两个元素都认为是不相同的,即每个元素只能出现一次。
无序性:一个集合中,每个元素的地位都是相同的,元素之间是无序的。
Set的操作比较少,基本上也就是Collection传下来的方法
Set一般基于Map来实现:HashSet、LinkedHashSet、TreeSet的特性,根本上是HashMap、LinkedHashMap、TreeMap的特性
1.HashSet
HashSet内部有一个HashMap<E,Object> map成员变量,增删实际上是使用map的方法
按照哈希的顺序:hashCode(),equals(Object obj)
底层实现:HashMap
private transient HashMap<E,Object> map;
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
2.LinkedHashSet
LinkedHashSet是HashSet的子类,源码少得可怜,基本上都是调用父类(HashSet)的构造方法
基于一个由链表实现的哈希表,保留了元素插入顺序
底层实现:LinkedHashMap
LinkedHashSet中:
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
HashSet中的三参构造
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
3.TreeSet---有序集合
实现NavigableSet:使用元素的compareTo对元素进行排序,也可使用Comparator自定义比较器
TreeSet多拜了一个师傅:NavigableSet-->SortedSet 使用方法也多几个
底层实现:TreeMap
public TreeSet() {
this(new TreeMap<>());
}