集合
集合分为俩大类
- 单列集合
- 每个元素数据只包含一个值
- 双列集合
- 每个元素包含俩个键值对
Conllection单列集合
单列集合常用的主要是下列几种
List集合
List系列集合的特点:添加元素是有序、可重复、有索引
这里我们来试一下ArrayList
ArrayList<String> list = new ArrayList<>();
list.add("java1");
list.add("java2");
list.add("java1");
list.add("java2");
System.out.println(list);
ArrayList底层原理
基于数据实现
特点:索引查询快,添加删除慢
-
利用无参构造器创建集合,会在底层创建一个默认长度为0的数组
-
添加第一个元素,底层会创建一个新的长度为10的素组
-
存满时,会扩容1.5倍
-
如果一次添加多个数据,1.5倍还放不下,则会以实际为准
应用场景
适合
:根据索引查询数据,比如根据随机索引取数据,或者数据量不是很大的不适合
:数据量大的同时,又要频繁的进行增删操作
LinkedList底层原理
基于双链表实现
特点:查询慢、增删快,尤其是首尾节点速度
应用场景
-
设计队列 (queue适用于校号系统、排队系统)
/** * 模拟队列 */ LinkedList<String> queue = new LinkedList<>(); //入队 queue.addLast("第一个人"); queue.addLast("第二个人"); queue.addLast("第三个人"); queue.addLast("第四个人"); System.out.println(queue); //出队 System.out.println(queue.removeFirst()); System.out.println(queue.removeFirst()); System.out.println(queue.removeFirst()); System.out.println(queue);
-
设计栈(Stack)
/*
* 模拟栈
* */
LinkedList<String> stack = new LinkedList<>();
//入栈
stack.push("第一颗子弹");
stack.push("第二颗子弹");
stack.push("第三颗子弹");
stack.push("第四颗子弹");
System.out.println(stack);
//出栈
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack);
注意这里的 push 和 pop 就是addfirst 和 removeFirst
Set集合
Set系列集合的特点:添加元素是无序、不可重复、无索引
注意这俩个特别:
- LinkedHashSet:
有序
、不重复、无索引 - TreeSet:
按照大小默认升序排序
、不重复、无索引
然后我们来试一试HashSet集合
HashSet<String> set = new HashSet<>();
set.add("java1");
set.add("java2");
set.add("java1");
set.add("java2");
System.out.println(set);
HashSet底层原理
基于哈希表实现
特点:增删改查都较好
1.8之前
JDK8之前哈希表:数组+链表
-
创建一个默认为16的数组
默认加载因子为0.75
表名为table -
使用元素的
哈希值
对数组长度求余
计算出应存入的位置(这里的求余是它独有的算法,并不是我们直接的%求余,确保它为正数) -
判断当前位置是否为null,如果是null直接存入
-
如果不为null,如果有元素,则调用equals方法比较(相等,则不存;不相等,则存入数组)
- JDK8之前,新元素会存入数组,占用老元素位置,老元素挂在下面
1.8之后
JDK8之后哈希表:数组+链表+红黑树
当链表长度超过8
,且数组长度>=64时
,自动将链表转为红黑树
LinkedHashSet底层原理
基于哈希表来实现
但是,每个元素都多了一个
双链表
机制来记录前后元素的位置
TreeSet底层原理
特点:可排序(默认升序,按照元素大小,由小到大)
底层基于红黑树实现
总结
集合并发修改异常错误
使用迭代器遍历集合时,又同时在删除集合中的数据,程序就会出现并发修改异常的错误。
底层原因是因为集合删除后会改变原集合的大小,而指针会自动往后移造成数据的漏删
例如
//删除名中有李字的
["张三","李四","五李","王五"]
i
//第一次
["张三","李四","五李","王五"]
i
//删除 后指针指向五李
["张三","五李","王五"]
i
//继续
["张三","五李","王五"]
i
上面这种情况就会造成异常错误
解决方法呢,就是在每次删除之后将i向前移
,迭代器底层也是这样实现的
Map双列集合
每次存储需要一对数据作为一个元素
Map中的键是不允许重复的,但是值可以
HashMap底层原理
特点:无序、不重复、无索引
底层:基于哈希表实现
实际上:原来所有的Set系列的集合都是基于Map实现的,只是Set集合中的元素只要键数据,不要值数据
注意的是底层这里计算hash值是基于键来
进行hash表计算
LinkedHashMap底层原理
特点:有序、不重复、无索引
底层:基于哈希表实现,但是多了一个
双链表
机制来记录元素顺序(保证有序)
实际上:原来学习的LinkedHashSet集合的底层原理就是LinkedHashMap。
TreeMap底层原理
特点:不重复、无索引、可排序(按照键的大小默认升序排序,只能对键排序)
原理:跟TreeSet一样基于红黑树实现排序