Java基础之集合总结

集合总结(Jdk8+)

一、单列集合(实现Collection接口)

在这里插入图片描述

1、结构关系

Collection(单列集合根接口):

  • List(子接口):
    • ArrayList(子接口实现类)
    • LinkedList(子接口实现类)
    • Vector(子接口实现类)
  • Set(子接口)
    • HashSet(子接口实现类)
    • LinkedHashSet(子接口实现类)
    • TreeSet(子接口实现类)

2、List和Set两个子接口的区别

2.1、List
  • List接口下的集合对象存储的数据有序性可重复性 (“动态”数组)
2.2、Set
  • Set接口下的集合对象储存的数据无序性不可重复性
  • 无序性:不等同于随机性,此处的无序性也是按照底层的某种规则进行的遍历
  • 不可重复性:每个要添加的元素都执行了hashCode方法,得到的哈希值和已添加的元素的哈希值进行判断(效率低);然后进行equals判断,返回true,添加失败;反之,添加成功

3、List接口实现类底层分析(源码分析)

3.1、ArrayList
  • ArrayList底层是数组

  • 调用无参构造创建集合对象:ArrayList list = new ArrayList();无参构造初始化数组为“{ }”;没有明确数组的长度,从而减小了内存的消耗;一旦开始往集合里面添加数据,就先初始化一个长度为10的数组;如果数组长度不够用,数组就会以1.5倍进行扩容,并将原来数组的数据复制到新扩容的数组中(延迟了数组的创建,节省内存)

  • 一般建议调用有参构造方法,直接给定数组的大小;避免了“动态扩容”提高效率

3.2、LinkedList
  • LinkedList底层是双向链表

在这里插入图片描述

3.3、Vector
  • 无参构造初始化数组长度为10;扩容倍数2
  • 线程安全,但效率低
3.4、ArrayList、LinkedList、Vector三者的区别

相同:

  • 三个实现类都实现了List接口
  • 存储的都是有序、可重复数据

不同点:

  • ArrayList(底层:Object[ ] elementData数组):List接口的主实现类,线程不安全但是效率高,适合查询操作(数组有下标)
  • LinkedList(底层:双向链表):适合频繁插入和删除的集合,在这种情况下比ArrayList效率高
  • Vector(底层:Object[] elementData数组):List接口的老实现类,线程安全但是效率低

4、Set接口实现类底层分析(源码分析)

4.1、HashSet
  • HashSet底层是数组+链表
  • Set接口的主实现类
  • 线程不安全,但是可以存null值
4.2、LinkedHashSet
  • HashSet的子类
  • 在添加数据的同时,还在每个元素的前面和后面添加了两个“指针”来分别指向上一个和下一个元素,因此遍历内部数据时,可以按照顺序进行遍历
  • 优点:LinkedHashSet的遍历效率高于HashSet
4.3、TreeSet
  • TreeSet底层是红黑树
  • 可以按照添加的对象的属性进行排序(自然排序、指定排序)
  • 向TreeSet对象中添加数据,必须是相同类型的对象
4.4、以HashSet为例,来理解HashSet添加数据的过程
  • 首先计算添加元素的哈希值
  • 根据某种算法(类似模运算,取余)来计算出该元素在HashSet底层数组的存放位置(数组的索引位置)
  • 判断该位置是否有元素
    • 无:直接插入
    • 有:一个(或多个元素-以链表的形式存放)比较哈希值
      • 哈希值相同:不能插入该元素(插入失败)
      • 哈希值不同:调用equals方法逐个比较
        • 返回true:不能插入该元素(插入失败)
        • 返回false:可以插入,将数组中的元素替换出来,原来的元素放到链表

二、双列集合(实现Map接口)

1、结构关系

Map(双列集合根接口):

  • HashMap(接口实现类)
    • LinkedHashMap(HashMap子类)
  • Hashtable(接口实现类)
    • Properties(Hasntable子类)
  • TreeMap(接口实现类)

2、Map接口实现类底层源码分析

2.1、HashMap
  • 底层:数组+链表+红黑树
  • 线程不安全,但是效率高
  • key和value能存储null
1、LinkedHashMap(HashMap的子类
  • 保证在遍历map对象时,可以按照添加的顺序来遍历
  • 在原有HashMap的底层结构基础上,添加了一对指针,分别指向前一个和后一个元素
  • 对于频繁的遍历元素,LinkedHashMap的效率高于HashMap
2.2、Hashtable
  • 作为Map的古老实现类
  • 线程安全,但是效率低
  • key和value不能存储null
1、Properties(HashTable子类
  • 常用来处理配置文件
  • 它的key和value都是String类型
2.3、TreeMap
  • 底层:红黑树
  • 保证按照添加的key和value键值对来进行排序(和单列集合中的TreeSet实现类类似),这里按照key来进行排序(自然排序和定制排序)
2.4、HashMap底层分析
1、HashMap底层
  • 数组+链表(jdk7及以前)
  • 数组+链表+红黑树(jdk8之后)
2、HashMap底层实现原理(jdk7)
  • 调用无参构造方法实例化集合(HashMap hashMap = new HashMap()),底层初始化长度为16的一维数组Entry[ ] table
  • 在实例化的集合对象中,put添加数据:key1-value1
  • 首先调用key1所在类的hashCode方法计算哈希值,然后根据特定算法,根据哈希值计算出Entry对象要存放的索引位置;先判断该位置有没有其他元素占用;
    • 如果该位置没有元素,那么直接插入(情况一)
    • 如果该位置有元素(一个或者多个元素以链表的形式存在),那么需要与该位置所有元素的哈希值进行比较
      • 哈希值不同,那么直接插入(情况二)
      • 哈希值相同,继续比较:调用key1所在类的equals方法进行比较
        • 返回false,那么直接插入(情况三)
        • 返回true,使用value1替换里面相同的value2

补充:

  • 针对情况二和情况三,此时key1-value1和其他数据以链表的形式存放
  • 在不断添加的过程中,会遇到扩容的问题,默认的扩容方式:扩容为原来的两倍,将原数组的数据复制到新的数组中
  • 注意:扩容时机有个临界值,并不是数组存满的时候进行扩容>0.75
3、HashMap底层实现原理(jdk8相比于jdk7在底层方面实现的不同)
  • 调用无参初始化数组时,没有给定数组长度
  • jdk8底层的数组时Node[ ] 而不再是Entry[ ]
  • 首次使用put添加数据初始数组长度为16
  • jdk7底层:数组+链表;jdk8底层:数组+链表+红黑树
    • 当数组某一个索引位置上的元素以链表的形式存放,数据个数>8且当前数组长度>64,此时索引位置上的所有数据,改为使用红黑树进行存储
2.5、说明
  • ArrayList和HashMap都是线程不安全的;如果程序要求线程安全,一般的做法就是,我们可以将ArrayList和HashMap转换成线程安全的(Collections工具类下的方法
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凉水不好喝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值