集合其实就是一个可以自动扩容的数组,它有一个默认长度,List的默认长度是10,增长因子是0.5;Set,Map默认长度为16,增长因子为0.75。但他们的具体原理又不一样,实现类也不一样,接下来,让我们一起去回顾一下吧!
首先它的实现类有:arraylist,LinkedList,Vector,CopyOnWriteArrayList。
arraylist是list最常用的实现类,但它其实是线程不安全的,但是是放在类变量的时候是不安全的,如果作为成员变量,方法变量其实安全的,因为这不存在线程安全不安全的问题。array list的内部就是封装好的数组, 所以它额随机访问速度在list中是最快的,但如果是集合的使用的话,如果它的数据访问量较小,那么list的随机访问速度要快,如果是数据的访问量大的话,HashMap 的访问速度肯要比array list要快。
在这里我们在回顾一下我们的list删除的时候要注意的点
- package com.zking.test;
-
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
-
- import org.junit.Before;
- import org.junit.Test;
-
- public class Tesylist {
- List<Integer> list;
-
- @Before
- public void setup() {
- list = new ArrayList<Integer>();
- list.add(1);
- list.add(4);
- list.add(8);
- list.add(8);
- list.add(12);
- list.add(16);
- }
-
- /**
- * 删除元素为8的元素
- */
-
- @Test
- public void listDel01() {
- for (int i = 0; i < list.size(); i++) {
- if (list.get(i) == 8)
- list.remove(i);
- }
- System.out.println(list);
- // 结果:[1,4,8,12,16],这种方式直接找到第一个元素8,找到后直接删除结束
-
- }
-
- @Test
- public void listDel02() {
- for (int i = 0; i < list.size(); i++) {
- if (list.get(i) == 8)
- list.remove(i--);
- }
- System.out.println(list);
- // 结果:[1,4,12,16] 这种方式找到第一个8 删除,但第二个8同时发生移位,
- // 直接跳到第一个8 的位置,但此时指针还未移动,所以又删除一个8 后才往下据继续移动
-
- }
-
- @Test
- public void listDel03() {
- for (int i = list.size() - 1; i >= 0; i--) {
- if (list.get(i) == 8) {
- list.remove(i);
- }
- }
- System.out.println(list);
- // 结果:[1,4,12,16] 这种方式是将集合到过来进行遍历删除,第二个8发生移位但又移动
- // 到了指针还为移动位置,然后删除了
-
- }
-
- @Test
- public void listDel04() {
- for (Integer i : list) {
- if (i == 8)
- list.remove(i);
- }
- System.out.println(list);
- // 结果:执行错误
-
- }
-
- @Test
- public void listDel05() {
- Iterator<Integer> it = list.iterator();
- while (it.hasNext()) {
- if (it.next() == 8) {
- it.remove();
- }
- }
- System.out.println(list);
- // 结果:[1,4,12,16]迭代器
-
- }
-
- @Test
- public void listDel06() {
- Iterator<Integer> it = list.iterator();
- while (it.hasNext()) {
- Integer value = it.next();
- if (value == 8) {
- list.remove(value);
- }
- }
- System.out.println(list);
- // 结果:执行不通过
- }
-
- @Test
- public void listDel07() {
- // ist.add(1);
- // list.add(4);
- // list.add(8);
- // list.add(8);
- // list.add(12);
- // list.add(16);
-
- list.add(4);
- // 结果: [1,4,8,12,16],在这里,删除的是下标为4的元素,刚好为元素8
- list.remove(Integer.valueOf(4));
- System.out.println(list);
- // 结果: [1,8,8,12,16],在这里,删除的是元素为4的元素,以为通过
- // integer.valueof()将4转成了一个对象4,所以删除的是4而不是下标为4的元素
- }
- }
说完这个array list,我们在来说一下这个其他的实现类
1. linkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部
2. 线程不安全
3. LinkedList可被用作堆栈(stack)【包括了push,pop方法】,队列(queue)或双向队列(deque)
4. 以双向链表实现,链表无容量限制,允许元素为null,线程不安全
5. 适合做随机的增加或删除
1. 线程安全
2. 并行性能慢,不建议使用
这个实现类有点意思,因为它是采用的是写实复制的一种最终一致性的实现类,它线程安全,性能比vector的高。
1.写时复制
2. 线程安全
3. 适合于读多,写少的场景
4. 写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array
5. 比Vector性能高
6.最终一致性
7.实现了List接口,使用方式与ArrayList类似
缺点:要等数据修改完了之后才能读取到,在修改数据时别人无法读取新数据,但值得一提的是在在复制和替换的时候这个时间是非常短的,所以我们也可以放心大胆使用。
这里提供一个详细的李斯特讲解的博客
李斯特详解
https://blog.csdn.net/weixin_67150631/article/details/125475936
和list不一样
1. 特点:无序,不重复
2. 遍历:foreach,迭代器
3. 扩容: 初始容量16,负载因子0.75,扩容增量1倍
李斯特可以重复元素,然后又顺序,但按list的内容进行删除的时候如果不注意可能会出现问题,在这里我也提供一个链接,介绍了set和List为什么删除会出错的原因
Set详解
https://blog.csdn.net/weixin_67150631/article/details/125491767
1.它存储唯一元素并允许空值,依据对象的hashcode来确定该元素是否存在
2. 由HashMap支持
3. 不保持插入顺序
4. 非线程安全
5. 性能参数:初始容量,负载因子,默认值: 初始容量16,负载因子0.75,示例:new HashSet<>(20, 0.5f);
1. 是一个包含有序的且没有重复元素的集合
2. 作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序
3. TreeSet是基于TreeMap实现的
1.默认自然排序
2.自定义排序
--1. 较器通过构造函数传入比
--2. 实现排序接口
这俩种排序方法在上面的连接中有详细介绍,我就不多介绍了
小结:Set和list都是继承的 Collection接口,而下面讲的Map却是继承单独的Map接口。
特点:
1.无序,键值对,键不能重复,值可以重复,这里的无序指的也是插入的顺序和读取的顺序是不一样的,和set集合一样。
2. 键重复则覆盖,没有继承Collection接口,它单独继承Map接口,和list,set不一样,这两个继承collection接口
扩容:
初始容量16,负载因子0.75,扩容增量1倍
遍历:
先获取所有键的Set集合,再遍历(通过键获取值)取出保存所有Entry的Set,再遍历此Set即可。
HashMap,HashTable,ConcurrentHashMap,TreeMap,LinkedHashMap
最有意思的是这HashMap,因为它的底层原理可以说是链表结构加红黑树的结构,当你的数据没有超过8的时候,在hashmap桶中就会是一个链结构,当你数据超过8了,你的数据结构就会变成一个红黑数的结构来存储,这样的结构在我们读取数据的时候会更快。
1. 线程不安全,最常用,速度快
2. 内部采用数组来存放数据
线程安全,不太常用,与vector类似,将所有数据加一把锁,性能很高
线程安全,比HashTable性能高,jdk1.8之前采用16把分段锁,将数据加锁,jdk1.8之后是每一个在数组的桶加锁,每一个桶一把锁,有多少桶就加多少锁,中间在赋值的时候才用的是cas,比较并替换。
key值按一定的顺序排序,添加或获取元素时性能较HashMap慢,因为需求维护内部的红黑树,用于保证key值的顺序
继承HashMap LinkedHashMap是有序的,且默认为插入顺序
当我们希望有顺序地去存储key-value时,就需要使用LinkedHashMap了
代码实现:
- Map<String, String> linkedHashMap = new LinkedHashMap<>();
- linkedHashMap.put("name1", "josan1");
- linkedHashMap.put("name2", "josan2");
- linkedHashMap.put("name3", "josan3");
- Set<Entry<String, String>> set = linkedHashMap.entrySet();
- Iterator<Entry<String, String>> iterator = set.iterator();
- while(iterator.hasNext()) {
- Entry entry = iterator.next();
- String key = (String) entry.getKey();
- String value = (String) entry.getValue();
- System.out.println("key:" + key + ",value:" + value);
- }
想了解更为详细的Map知识的直接去这里:
Map详解
https://blog.csdn.net/weixin_67150631/article/details/125511020
欢迎一键三连