Java的集合类主要由两个根接口Collection和Map派生而出。集合框架中所有具体类都实现了Cloneable和Serializable接口。
Set:存储一组不重复的元素,继承了Collection,主要有2个实现方式:
1.TreeSet(依赖于TreeMap,实际上通过TreeMap实现):
子类LinkedHashSe使用链表扩展实现HashSet类,支持对元素排序,打印时顺序与添加时的顺序一致。
2.HashSet(依赖于HashMap,实际上通过HashMap实现):
打印时有序,默认字符串比较的顺序,也可以排序.
HashSet中是允许存入null值的,但是在HashSet中仅仅能够存入一个null值。
List,继承了Collection:
实现类:LinkedList, ArrayList, Vector, Stack(Stack继承自Vector,比较古老)。
ArrayList是一个动态数组,每一个ArrayList都有一个初始容量(10).擅长于随机访问。同时ArrayList是非同步的。
LinkedList是一个双向链表,不能随机访问,LinkedList也是非同步的。
Vector:与ArrayList相似,但是Vector是同步的。所以说Vector是线程安全的动态数组。它的操作与ArrayList几乎一样。
Map(与collection没什么关系):默认情况下只能对键排序
HashMap:无序
LinkedHashMap:和插入顺序一致
treeMap:按键排序
三种遍历map的方法
Map<String,Integer> treeMap = new TreeMap<>();
treeMap.put("abc", 1);
treeMap.put("ABC", 2);
treeMap.put("xyz", 3);
treeMap.put("XYZ", 4);
System.out.println("treeMap:" +treeMap);
System.out.println("第一种遍历方式:通过Map.keySet遍历key,通过key取出对应的value值");
for (String key : treeMap.keySet()) {
System.out.println(key + "--" + treeMap.get(key));
}
// 一键一值 => entry
System.out.println("第二种遍历方式:通过Map.entrySet使用迭代器遍历key和value");
Set<Map.Entry<String,Integer>> entrySet = treeMap.entrySet();
Iterator<Entry<String, Integer>> entrySetIt = entrySet.iterator();
while(entrySetIt.hasNext()){
Map.Entry<String, Integer> entry = entrySetIt.next();
System.out.println(entry.getKey() + "--" + entry.getValue());
}
System.out.println("第三种遍历方式:直接遍历Map.entrySet集合---容量大时使用");
for(Entry<String,Integer> entry : treeMap.entrySet()){
System.out.println(entry.getKey() + "--" + entry.getValue());
}
队列:
队列是数据结构中比较重要的一种类型,它支持 FIFO,尾部添加、头部删除(先进队列的元素先出队列),跟我们生活中的排队类似。
队列有两种:
- 单队列
- 循环队列
单队列就是常见的队列, 每次添加元素时,都是添加到队尾:
以数组实现的队列为例,初始时队列长度固定为 4,font 和 rear 均为 0:
每添加一个元素,rear 后移一位。当添加四个元素后, rear 到了索引为 4 的位置:
这时 a1,a2 出队,front 后移动到 2:
这时想要再添加两个元素,但 rear 后移两位后就会越界:
明明有三个空位,却只能再放入一个!这就是单队列的“假溢出”情况。
(上述参考借鉴自 http://www.nowamagic.net/librarys/veda/detail/2350)
针对这种情况,解决办法就是后面满了,就再从头开始,也就是头尾相接的循环。这就是 “循环队列” 的概念。
循环队列:
循环队列中,
rear = (rear - size) % size
接着上面的例子,当 rear 大于 队列长度时,rear = ( 5 - 5) % 5 = 0 :
这样继续添加时,还可以添加几个元素:
那如何判断队列是否装满元素了呢,单使用 front == rear 无法判断究竟是空的还是满了。
两种方法:
- 加个标志 flag ,初始为 false,添加满了置为 true;
- 不以 front = rear 为放满标志,改为 (rear - front) % size = 1。
法 2 的公式放满元素时空余了一个位置,这个公式是什么意思呢?
当 rear < font 时,队列中元素分为两部分: size - font 和 rear ,也就是 rear + size - font。以上述图片为例,队列中元素个数 = 1 + 5 - 2 = 4.
Queue(存储用先进先出方式处理的对象):
Blocking Queue
Abstract Queue
Deque(双端队列,支持从两端操作队列元素
--LinkedList
--ArrayDeque
ArrayDeque-一个基于数组实现的双端队列,默认底层数组长度为16,当元素超过集合容量时,系统会在底层重新分配一个Object数组来存储数据。
Deque 的实现类主要分为两种场景:
- 一般场景
- LinkedList 大小可变的链表双端队列,允许元素为 null
- ArrayDeque 大下可变的数组双端队列,不允许 null并发场景
- LinkedBlockingDeque 如果队列为空时,获取操作将会阻塞,知道有元素添加
并发场景
- LinkedBlockingDeque 如果队列为空时,获取操作将会阻塞,知道有元素添加