辞职啦,嘻嘻嘻,写个集合小结,为下一份工作蓄力!

集合

19号和领导提了辞职,虽然领导极力挽留(加钱很有诚意啦,哈哈哈),但还是觉得跑路啦,保险行业太注重业务啦,还是想趁这年轻去接触更多的技术,冲冲冲。
写这篇文章也是为了复习复习哈哈哈,准备准备面试,写了好多,感觉有些东西自己也不是很确定没不知道有没有大佬帮忙指点以下,哈哈哈哈。

List

List为有序,可重复的的集合,可以精确的控制元素插入的位置,亦可以通过索引来快速的访问元素。

List的实现类有ArrayList、LinkedList和Vector。其中ArrayList及Vector的底层实现均为数组,而LinkedList的底层实现为链表结构。区别的话在于数组结构的可以更快的进行查询,而在增加删除元素时需要移动很多元素,而效率不高(效率的快慢取决于元素的位置)。而链表结构的因为每次查询都需要从头开始,而查询效率不高,但增加删除只需要断开链表添加删除即可,而效率优于数组结构。三个中只有Vector为线程同步的,因此效率上也是不如ArrayList。

关于占用内存及扩容 。ArrayList的内存方面的浪费是因为一般在结尾会预留一定的内容空间,而LinkedList因为底层实现为双向链表,在存储是因为不仅存储元素还需要存储前驱和后继,所以更浪费空间。当其容器内存不足时,需要进行扩容,扩容的方法就是重新分配一个新数组,然后复制元素到新数组中,再将元素添加到数组末位,所以有必要在创建时就计算好大致需要的内存。其中ArrayList会将存为原来的1.5倍,而Vector则会扩为原来的2倍。而linkedList 是一个双向链表,没有初始化大小,也没有扩容的机制,就是一直在前面或者后面新增就好。

Set

Set为无序,不可重复的集合,没有索引,所以只能提供增强for或者迭代器来进行遍历。HashSet是Set接口的主要实现类 ,HashSet的底层是HashMap,线程不安全的,可以存储 null 值;LinkedHashSet是 HashSet 的子类,能够按照添加的顺序遍历;TreeSet 底层使用红黑树,能够按照添加元素的顺序进行遍历,排序的方式有自然排序和定制排序。

​ 说到Set集合就必须说到哈希值,哈希值是Jdk根据对象的地址或者字符串、数字生成的int类型数值(默认情况下,不同对象的哈希值不同,但通过重写hashcode方法可以让不同的对象获得相同的hashcode值)。

​ HashSet的底层为Hash表,因为是Set集合,同样也为无序,不可重复的集合,没有索引。看了HashSet的源码发现在基本上都是实现了HashMap,所以默认的大小也是为16,负载因子为0.75(还有个实现了LinkedHashMap),当容量达到负载因子时就会自动扩容。

image-20210524221142298

​ HashSet在添加元素时会计算元素的hashcode,然后找到对应的插入位置(若hashcode为100001,散列单元为10,100001%10=1,其实也是与下面说到的hashmap相同),若对应的位置没有元素则直接插入,若有元素将比较两个元素的hashcode值,若不相同则直接插入,若相同则将调用equals()方法对比两个元素的内容,若不相同才进行存储。这也是HashSet保证元素不重复的机制。

Map

Map中存储的为键(k)值(v)对,每个键对应一个值。常见的Map有HashMap、Hashtable、ConcurrentHashMap、LinkedHashMap、TreeMap。 HashMap根据键的hashcode值来存储对象,根据键可以直接获取它的值,具有很快的访问速度只允许一条记录的键为Null(多条会覆盖)但允许多条记录的值为 Null且非同步的。Hashtable与 HashMap类似,不同的是:key和value的值均不允许为null且它支持线程的同步,所以在效率上不如HashMap。LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.在遍历的时候会比HashMap慢,key和value均允许为空且非同步的。 TreeMap能够把它保存的记录根据键(key)排序,默认是按升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。TreeMap不允许key的值为null。非同步的。

​ 其中最常用的为HashMap,多线程的情况下使用ConcurrentHashMap,这也与它们的特性有关。HashMap是线程非安全的,效率比较高;HashTable和CurrentHashMap是线程安全的,效率比HashMap差一点,但CurrentHashMap比HashTable更加高效一些,因为CurrentHashMap(JAVA5)采用了更加高效的分段锁机制,HashTable基本已经弃用了。

​ HashMap存储键值对时调用键对象的hashCode()方法来计算hashcode,然后找到对应的bucket位置来储存值对象(包含键和值 ),关于具体的存储位置算法,我们首先可能会想到采用%取余的操作来实现。但是取余(%)操作中如果除数是 2 的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1),但前提是 length 是 2 的 n 次方,并且 采用二进制位操作 &,相对于%能够提高运算效率,这就解释了 HashMap 的长度为什么是 2 的幂次方,这也是HashMap的的长度为什么总是设定2的幂的原因,HashMap中也是有方法来保证大小总是为2的幂。HashMap底层是数组和链表,HashMap使用链表来解决碰撞问题,当发生碰撞了,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不同的话对象将会储存在链表的下一个节点中,即 HashMap是通过链表结构存储hashcode相同的键值对。

​ JDK1.8 之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。

​ 当一个map的容量达到75%时(填满了75%的bucket),将触发扩容机制,和其它集合类(如ArrayList等)一样,将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫作rehashing,因为它调用hash方法找到新的bucket位置。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值