Java常见集合

list、set、map

Arraylist 与 LinkedList 区别?

  1. 是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
  2. 底层数据结构: Arraylist 底层使用的是 Object 数组;LinkedList 底层使用的是 双向链表 数据结构(JDK1.6 之前为循环链表,JDK1.7 取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)
  3. 插入和删除是否受元素位置的影响:查找元素的时间复杂度+插入元素的时间复杂度

 ① ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是 O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element))时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② LinkedList 采用链表存储,所以对于add(E e)方法的插入,删除元素时间复杂度不受元素位置的影响,近似 O(1),如果是要在指定位置i插入和删除元素的话((add(int index, E element)) 时间复杂度近似为o(n))因为需要先移动到指定位置再插入。

  1. 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而 ArrayList 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。
  2. 内存空间占用: ArrayList 的空 间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)。

这两种集合哪个比较占内存?(看情况的,ArrayList如果有扩容并且元素没占满数组的话,浪费的内存空间也是比较多的,但一般情况下,LinkedList占用的内存会相对多点,因为每个元素都包含了指向前后节点的指针)

ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在

Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。

为什么 ArrayList 的 elementData 加上 transient 修饰?

ArrayList 实现了 Serializable 接口,这意味着 ArrayList 支持序列

化。transient 的作用是说不希望 elementData 数组被序列化。既加快了序列化的速度,又减小了序列化之后的文件大

多线程场景下如何使用 ArrayList?实现线程安全的list

通过Vector、Collections.synchronizedList()方法和CopyOnWriteArrayList三种方式

读多写少的情况下,推荐使用CopyOnWriteArrayList方式

读少写多的情况下,推荐使用Collections.synchronizedList()的方式

说一下 HashSet 的实现原理?

HashSet 是基于 HashMap 实现的,HashSet的值存放于HashMap的key上,HashMap的value统一为

PRESENT,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层

HashMap 的相关方法来完成,HashSet 不允许重复的值。

HashSet 中的add ()方法会使用HashMap 的put()方法。

HashMap:数组+链表存储key-value键值对,

jdk7,链表,查找时间复杂度为O(n) ,数据增大n倍,复杂度增加n倍

jdk8,链表长度大于8,链表转红黑树,查找时间复杂度为O(logN),数据增大n倍,复杂度增加logN倍,如增加256倍,复杂度增加8倍

将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树

为什么数据+链表?

数组是用来确定桶的位置,利用元素的key的hash值对数组长度取模得到.

链表是用来解决hash冲突问题,当出现hash值一样的情形,就在数组上的对应位置形成一条链表。

ps:这里的hash值并不是指hashcode,而是将hashcode高低十六位异或过的,保证了对象的 hashCode 的 32 位值只要有一位发生改变,整个 hash() 返回值就会改变。尽可能的减少碰撞。

HashMap的扩容操作是怎么实现的?

①.在jdk1.8中,resize方法是在hashmap中的键值对大于阀值时或者初始化时,就调用resize方法进行扩容;

②.每次扩展的时候,都是扩展2倍;

③.扩展后Node对象的位置要么在原位置,要么移动到原偏移量两倍的位置。

  1. HashMap 默认bucket数组多大?(答案是16)
  2. 如果new HashMap<>(19),bucket数组多大?(答案是32)
  3. HashMap 什么时候开辟bucket数组占用内存?(答案是第一次 put 时)
  4. HashMap 何时扩容?(答案是put的元素达到容量乘负载因子的时候,默认16*0.75)

HashMap 的长度为什么是2的幂次方

为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀。

因为在hashMap的length等于2的n次方的时候,才会有hash%length==hash&(length-1);哈希算法的目的是为了加快哈希计算以及减少哈希冲突,所以此时&(按位与)操作更合适,所以在length等于2的幂次方的时候,可以使用&操作加快操作且减少冲突,所以hashMap长度是2的幂次方

为什么这样能均匀分布减少碰撞呢?2的n次方实际就是1后面n个0,2的n次方-1 实际就是n个1;

当然如果不考虑效率直接求余即可(就不需要要求长度必须是2的n次方了)

取模运算是求两个数相除的余数

拉链法导致的链表过深问题为什么不用二叉查找树代替,而选择红黑树?为什么不一直使用红黑树?

选择红黑树是为了解决二叉查找树的缺陷,二叉查找树在特殊情况下会变成一条线性结构(这就跟原来使用链表结构一样了,造成很深的问题),遍历查找会非常慢。

而红黑树在插入新数据后可能需要通过左旋,右旋、变色这些操作来保持平衡,引入红黑树就是为了查找数据快,解决链表查询深度的问题,我们知道红黑树属于平衡二叉树,但是为了保持“平衡”是需要付出代价的,但是该代价所损耗的资源要比遍历线性链表要少,所以当长度大于8的时候,会使用红黑树,如果链表长度很短的话,根本不需要引入红黑树,引入反而会慢。

HashMap 和 ConcurrentHashMap 的区别

1. ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用lock锁进

行保护,相对于HashTable的synchronized 锁的粒度更精细了一些,并发性能更好,而HashMap

没有锁机制,不是线程安全的。(JDK1.8之后ConcurrentHashMap启了一种全新的方式实现,利用

CAS算法。)

2. HashMap的键值对允许有null,但是ConCurrentHashMap都不允许

HashMap的扩容因子默认0.75,也就是会浪费1/4的空间,达到扩容因子时,会将list扩容一倍,0.75 是时间与空间一个平衡

值;

ConcurrentHashMap 和 Hashtable 的区别?

ConcurrentHashMap 和 Hashtable 的区别主要体现在实现线程安全的方式上不同。

JDK1.7的 ConcurrentHashMap 底层采用 分段的数组+链表 实现,

JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。

Hashtable 和 JDK1.8 之前的 HashMap 的底层数据结构类似都是采用 数组+链表 的形式,

① 在JDK1.7的时候,ConcurrentHashMap(分段锁) 对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一

部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。(默认分配16

个Segment,比Hashtable效率提高16倍。) 到了 JDK1.8 的时候已经摒弃了Segment的概念,而是直接用

Node 数组+链表+红黑树的数据结构来实现,并发控制使用

synchronized 和 CAS 来操作

在JDK1.8中,放弃了Segment臃肿的设计,取而代之的是采用Node + CAS (无锁算法)+ Synchronized来保证并发

安全进行实现,synchronized只锁定当前链表或红黑二叉树的首节点,这样只要hash不冲突,就不会产

生并发,效率又提升N 倍。

jdk7的hashmap的死循环

ConcurrentHashMap 的并发度是什么?

程序运行时能够同时更新 ConccurentHashMap 且不产生锁竞争的最大线程数。默认为 16,且可以在构造函数中设置。

当用户设置并发度时,ConcurrentHashMap 会使用大于等于该值的最小2幂指数作为实际并发度(假如用户设置并发度为17,实际并发度则为32)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值