java集合整理

1. java集合的常规比较

(1)HashMap:初始容量16、扩容两倍、默认加载因子是0.75,extends AbstractMap implements Map,长度是2的幂次方能让HashMap存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀。hash%length==hash&(length-1)采用二进制位操作&,相对于%能够提高运算效率,这就解释了HashMap的长度为什么是2的幂次方。
(2)HashSet:初始容量16、扩容两倍、
(3)Hashtable:初始容量11、扩容2倍+1、extends Dictionary implements Map
初始容量为11的原因是除(近似)质数求余的分散效果好,创建时如果给定了容量初始值,那么Hashtable会直接使用你给定的大小
(4)ArrayList:jdk1.8之前,初始容量10、扩容1.5倍+1,JDK1.8以后是0,然后首次增加到10,以后每次增加到1.5倍,底层是Arrays的数组拷贝来实现的,implements List, RandomAccess, Cloneable, java.io.Serializable。
(5)StringBuffer、初始容量16、扩容2倍+2或者是count+str.length()
(6)Vector扩容两倍

2、JDK1.8中ConcurrentHashMap中的CAS和synchronized在哪使用的

CAS:在判断数组中当前位置为null的时候,使用CAS来把这个新的Node写入数组中对应的位置
synchronized:当数组中的指定位置不为空时,通过加锁来添加这个节点进入数组(链表<8)或者是红黑树(链表>=8)

3、Arrays.asList方法后的List可以扩容吗?

Arrays.asList使用的是final数组,并且不支持add方法,不支持扩容。

4、HashMap中hash函数做了哪些改动?(1.7->1.8)

让hashCode取值出的高位也参与运算,进一步降低hash碰撞的概率,使得数据分布更平均,我们把这样的操作称为扰动,在JDK1.8中的hash()函数如下:
(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
// 与自己右移16位进行异或运算(高低位异或)
这比在JDK1.7中,更为简洁,相比在1.7中的4次位运算,5次异或运算(9次扰动),在1.8中,只进行了1次位运算和1次异或运算(2次扰动)
注:回答Hashmap的时候,先从结构->put->扩容

5.hashmap中1.7和1.8的区别

(1)JDK1.7用的是头插法,而JDK1.8及之后使用的都是尾插法,那么他们为什么要这样做呢?因为JDK1.7是用单链表进行的纵向延伸,当采用头插法就是能够提高插入的效率,但是也会容易出现逆序且环形链表死循环问题。但是在JDK1.8之后是因为加入了红黑树使用尾插法,能够避免出现逆序且链表死循环的问题。

(2)扩容后数据存储位置的计算方式也不一样:

在JDK1.7的时候是直接用hash值和需要扩容的二进制数进行&(这里就是为什么扩容的时候为啥一定必须是2的多少次幂的原因所在,因为如果只有2的n次幂的情况时最后一位二进制数才一定是1,这样能最大程度减少hash碰撞)(hash值 & length-1)

而在JDK1.8的时候直接用了JDK1.7的时候计算的规律,也就是扩容前的原始位置+扩容的大小值=JDK1.8的计算方式,而不再是JDK1.7的那种异或的方法。但是这种方式就相当于只需要判断Hash值的新增参与运算的位是0还是1就直接迅速计算出了扩容后的储存方式。

(3)在计算hash值的时候,JDK1.7用了9次扰动处理=4次位运算+5次异或,而JDK1.8只用了2次扰动处理=1次位运算+1次异或。

(4)**JDK1.7的时候使用的是数组+ 单链表的数据结构。**但是在JDK1.8及之后时,使用的是数组+链表+红黑树的数据结构(当链表的深度达到8的时候,也就是默认阈值,就会自动扩容,把链表转成红黑树的数据结构来把时间复杂度从O(n)变成O(logN)提高了效率)

6. 如何解决哈希冲突

1.如果发生冲突时,jdk1.7采用链地址法+头插法,jdk1.8采用链地址法+尾插法+红黑树(链表长度大于8,且数组长度大于60)
2.二次扰动(jdk1.8是一次位运算一次异或,jdk1.7是4次位运算5次异或)
3.引入红黑树,jdk1.7之前复杂度是o(n),1.8是o(logn)

7.Comparable和Comparator的区别

相同点
两者都是用来用作对象之间的比较,都可以自定义比较规则;
两者都是返回一个描述对象之间关系的int;
区别:
1.comparable 在java.lang包下,comparator在java.util包下;
实现comparable 必须重写compareTo(T o),实现comparator必须重写compare(T o1,T o2);
2.comparable是内在比较器,表示这个类的对象直接可以相互比较this.compareTo(this),该类支持排序,这个类对象组成的集合就可以直接使用Collections.sort方法排序,此外,“实现Comparable接口的类的对象”可以用作“有序映射(如TreeMap)”中的键或“有序集合(TreeSet)”中的元素,而不需要指定比较器。comparator是外在比较器,如果想比较两个类又没有实现comparable或者想实现比较排序的,可以用Comparator.compara(o1,o2);
3.comparator 是典型的策略模式(策略模式指定义一组算法类,将每个算法实现封装起来,让他们可以相互替换,不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。)每个类都可以实现comparator,都可以实现比较排序;
4.Comparator与Comparable同时存在的情况下,比较器Comparator优先级高。
使用Comparable需要修改原先的实体类,是属于一种自然排序,而Comparator 是不用修改原先的类的实现一个新的比较器 。Comparator实际应用广,

8.HashMap在并发环境下会出现什么样的问题(环的问题)?

(1)Hashmap的Resize包含扩容和ReHash两个步骤,ReHash在并发的情况下可能会形成链表环。
(2)Hashmap在并发情况下还会造成size不准确(因为在判断是否需要扩容之前会做size++,其实这个时候size实际可能只是增加了1,现在确增加了2)

9.HashsSet为什么无序,为什么不重复?

hashset底层是哈希表,当一个对象存入hashset集合的时候,首先会计算hash值,如果hashcode值相同,那么就会调用equals,判断是否相等,如果不相等,证明他们不是一个对象,如果相等证明他们是一个对象,舍弃一个。

10.、ConcurrentHashMap的size()方法是如何计算的?

JDK1.7 和 JDK1.8 对 size 的计算是不一样的。1.7 中是先不加锁计算三次,如果三次结果不一样在加锁。
JDK1.8 size 是通过对baseCount和counterCell 进行 CAS 计算,最终通过 baseCount 和 遍历 CounterCell 数组得出 size。

11.ArrayList的底层实现、扩容过程、add过程、Fail-Fast机制;

jdk1.8之前,初始容量10、扩容1.5倍+1,JDK1.8以后是0,然后首次增加到10,以后每次增加到1.5倍,底层是Arrays的数组拷贝来实现的,implements List, RandomAccess, Cloneable, java.io.Serializable。

Fail-Fast机制也叫快速失败机制,当多个线程同时访问集合时,其中一个线程对集合做了改变,就有可能会发生fail-fast,即抛出 ConcurrentModificationException异常。

12 如何获得一个线程安全的List

第一种使用vector
第二种使用Collections.synchronizedList(List list)
第三种使用CopyOnWriteArrayList
建议插入操作的时候使用Collections.synchronizedList(List list),因为CopyOnWriteArrayList插入的时候会复制新建数组,比较耗内存。
读取操作多的时候使用CopyOnWriteArrayList,因为Collections.synchronizedList(List list)加了锁要慢一些。

13 Linkedlist的底层实现,以及如何使用LinkedList实现一个LRU

linkdlist底层是双向链表,在存储过程中无需像ArrayList一样扩容,linkdlist在多线程下线程是不安全的,linkdlist插入和删除比较快,只需要移动指针就行了,不需要判断是否需要扩容。

LRU(Least Recently Used),即最近最少使用,是一种常用的页面置换算法,如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最近最少使用的数据淘汰。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

轩成笔记

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

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

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

打赏作者

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

抵扣说明:

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

余额充值