Java面试--基础
ArrayList
ArrayList的扩容机制
add()方法:初始化未添加元素的ArrayList集合,长度是0,当添加第一个元素之后长度变成10,元素个数超过容量的时候自动扩容,每一次扩容都采用移位运算,n=n>>>1+n,即10变成10+10>>>1=10+5=15,15变成15+15>>>1=15+7=22.
addAll()方法:会比较加入的集合长度和扩容之后的长度,选择更长的作为集合的容量,比如10之后addAll()6个元素,扩容的长度为16,并不是22
FailFast和FailSafe?
FailFast:一旦发现遍历的同时其他人来修改,则立刻抛出异常,用于ArrayList、Vector
底层原理:每次遍历一个元素之前都调用如下方法,比较modCount(集合中元素的个数)的值,如果发现不一样抛出异常
FailSafe:发现遍历的同时其他人来修改,应当能有应对策略,例如牺牲一致性来让整个遍历操作正常运行,用于CopyOnWriteArrayList
底层原理:因为CopyOnWriteArrayList底层的add方法添加元素是直接将新的元素放入到新数组的最后以为,而遍历集合时候却用的是久的数组,所以牺牲了一致性,就算在遍历时其他人有修改操作,遍历的集合对象也是原集合
ArrayList和LinkedList?
实际开发中常用ArrayList,除了头部插入数据效率低于LinkedList,其他方面都优于或者等价于LinkedList
LinkedList插入中间位置效率不高:因为插入中间的过程中避免不了定位到插入元素的节点,所以还需要一次遍历操作来查询插入元素节点的下标,大大的降低了效率
局部性原理:ArrayList可以利用cpu缓存,一次性读取多个数据,因为ArrayList中数据的存放是规律的,方便cpu从缓存中读取数据,效率高
HashMap
介绍一下put方法流程,1.7和1.8有何不同?
负载因子默认值为何是0.75?
在多线程情况下HashMap会出现什么问题?
1.7:因为头插法导致的扩容死链
1.7、1.8:因为线程不安全导致的put时数据丢失