Java集合(含常见面试题)

1.分类
在这里插入图片描述在这里插入图片描述

List:存储的元素可重复、有序
Set:存储的元素不可重复
Map:key-value形式存储,key不可重复、无序,value可重复
2.List

  • ArrayList:底层是Object[]数组
  • Vector:底层是Object[]数组,操作都加了锁,是ArrayList的安全版本
  • LinkedList:底层是双向链表(JDK1.6之前是循环链表,JDK1.7取消了循环)

ArrayList和LinkedLis的区别?

1.线程安全性:都是不安全的。
2.底层数据结构:ArrayList底层是数组;LinkedList底层是双向链表
3.性能:ArrayList插入删除受位置影响O(n-i)。LinkedList添加删除(末尾)的复杂度为O(1),特定位置的话O(i).ArrayList支持随机访问,LikedList添加删除比较快。
4.空间:LinkedList占用空间更大,需要保存直接前驱和直接后继和数据。

3.Set

  • HashSet:无序,唯一,底层是HashMap实现,以Object常量作为value
  • LinkedHashSet:是HashSet的子类,内部是通过LinkedHashMap实现的,LinkedHashMap是基于链表哈希表实现的,所以LinkedHashSet是有序的。
  • TreeSet:基于红黑树,有序唯一

4.Map

  • HashMap:JDK1.8以前是基于数组+链表的结构,数组是存储不同哈希值的桶,链表是为了解决Hash冲突,如果两个不同的对象Hash值一样,就会添加在数组位的链表后面。JDK1.8以后是基于数组+链表或红黑树

当链表长度大于阈值(默认为8)(先判断当前数组是否小于64,如果是则先进行数组扩容,不是就将链表转化为红黑树)就将链表转化为红黑树,可以减少搜索时间。,当删除小于六时重新变为链表。

  • LinkedHashMap:LinkedHashMap继承了HashMap,底层在HashMap的基础之上,增加了一条双向链表,以键值对插入的顺序存储。
  • Hashtable:底层基于数组+链表的形式,线程安全
  • TreeMap:底层是红黑树
    为啥HashMap链表为8开始转换?

根据泊松分布,在负载因子默认为0.75的时候,单个hash槽内元素个数为8的概率小于百万分之一,所以将7作为一个分水岭,等于7的时候不转换,大于等于8的时候才进行转换,小于等于6的时候就化为链表。

想要使用线程安全的HashMap,该怎么做?

使用Collections.synchronizedMap(Map)创建线程安全的map集合;ConcurrentHashMap(性能更高);Hashtable

synchronizedMap如何实现线程安全的?

在SynchronizedMap内部维护了一个普通对象Map,还有排斥锁mutex。可以自己传入mutex参数,否则使用默认的。当HashMap对象作为参数时,HashMap的每个方法里面的代码块上锁。

Hashtable与HashMap的区别?

1.Hashtable的key和value都不能为null,HashMap可以。因为算hash值的时候会判断key如果为null就返回0,put空值的时候会抛空指针异常。因为Hashtable使用的是安全失败机制failt-safe,不直接访问集合,先拷贝一份访问副本,这种机制使得获取的数据不一定是最新的,但不会因为在遍历的时候更改了原集合而抛异常。
2.线程安全性:HashTable的方法都加了锁,是线程安全的,HashMap是非线程安全的
3.底层数据结构:JDK1.8以后HashMap新增了红黑树,而Hashtable没有改变。
4.扩容:Hashtable默认初始大小为11,每次扩容为原来的2n+1,HashMap默认初始容量为16.扩容为原来的两倍,且自定义大小也会变为2的幂次方,Hashtable不会。

fail-fast是什么?

快速失败(fail-fast) 是Java集合的一种错误检测机制。在迭代器遍历的时候,在多线程下操作非安全失败(fail-safe) 的集合类可能会触发fail-fast机制,抛出ConcurrentModificationException。如果在单线程情况下修改集合,也会导致fail-fast。
原理:hasNext()/next()遍历时,都会检测modCount是否为expectedmodCount,不是就会抛出异常。集合发生变化就会修改modCount。用Iterator的方法修改不会发生异常,因为同时也修改了expectedmodCount。

ConcurrentHashMap原理©、和HashMap(H)有什么不同?

1.底层数据结构:JDK1.7的C底层是分段的数组+链表,JDK1.8根HashMap一样
2.线程是否安全:JDK1.7时,C对整个桶(数组)进行了分割分段(Segment),加上了分段锁ReentrantLock)只锁容器的一部分数据,多线程访问容器的不同段时就不会冲突,提高并发效率(比Hashtable好)。JDK1.8摒弃了Segment,直接用Node数组+链表+红黑树实现,锁粒度降低了,且只锁头结点,hash不冲突,就不会产生并发问题,并发控制使用synchronized和CAS

为什么ConcurrentHashMap1.8改为synchronized?

1.因为粒度降低了,在相对而言的低粒度加锁方式,synchronized并不比ReentrantLock差,在粗粒度加锁中ReentrantLock可能通过Condition来控制各个低粒度的边界,更加的灵活,而在低粒度中,Condition的优势就没有了
2.JVM的开发团队从来都没有放弃synchronized,而且基于JVM的synchronized优化空间更大,使用内嵌的关键字比使用API更加自然
3.在大量的数据操作下,对于JVM的内存压力,基于API的ReentrantLock会开销更多的内存,虽然不是瓶颈,但是也是一个选择依据

为什么HashMap大小总是2的幂次方

添加数据时,要通过ab=[(n - 1) & hash] 计算出key对应数组的位置,本意是让hash值对数组的大小n进行取模,如果n的2的幂次方,那么就可以用(n-1)&hash代替%运算,且效率更高。所以为能用与运算代替取模运算,数组的大小必须是2的幂次方。

HashMap多线程发生死循环?

HashMap死循环问题分析

5.迭代器Iterator
对集合进行遍历,不用知道集合元素的类型,使用hasNext()和next()方法就可以对所有集合进行遍历。当遍历的过程中元素被修改,就会抛出ConcurrentModificationException的错误。

6.ConcurrentHashMap:是concurrent包下面的,可以看做是线程安全的HashMap。1.7基于Segment数组+ReentrantLock+链表,1.8基于Node数组+CAS+synchronized

参考:
Java集合中List,Set以及Map等集合体系详解(史上最全)
我把ConcurrentHashMap & HashTable的知识点都整理了一下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值