Java集合-----真实大厂面试题汇总(含答案)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36520235/article/details/86745780

面试题1. HashMap的扩容?

面话题2. 一个ArrayList在循环过程中删除,会不会出问题,为什么?

肯定会出现问题的,原因有以下几个:

  1. 如果要是使用的是 for (int i = 0; i < list.size();i++)这种for循环的话,当我要删除的这个List中有两个相同的元素值,而刚好我要删除这个相同的元素的话,就会导致的结果是只能删除掉第一个元素值
    原因:是因为在List中的API中的remove()方法底层删除的时候其实是调用了 System.arraycopy(elementData, index+1, elementData, index, numMoved);这个方法(elementData表示当前list,第二个elementData其实表示的是我要复制到的目的List,index+1是当前List的下标起始位置),在删除第一个元素之后,会把删除元素后面的所有元素都往前移动,刚好把第二个和第一个相同的元素的值补到刚刚删除的空位置下,但是继续遍历的时候是从刚刚删除的那个元素下标之后开始,所以刚好把第一个元素和 他相同的第二个元素跳过去
    解决办法:就是进行倒序删除元素,就可以避免这种情况的发生。

  2. 如果使用foreach,比如在使用for (String s : list)的时候 ,调用了remove()的话,就会出现java.util.ConcurrentModificationException这个错误。
    原因是因为:foreach写法是对实际的Iterable、hasNext、next方法的简写,问题同样处在上文的fastRemove方法中,第一句代码就是modCount++,但是在checkForComodification()方法中会对list中记录的修改的次数(modCount )和开始期望的list的修改次数(expectedModCount他是初始化的时候就已经固定了 )进行判断,如果跟预期的list的修改次数不一样的时候就会报错。,这里其实是基于Fail-Fast的机制。

    在一个迭代器初始的时候会赋予它调用这个迭代器的对象的mCount,如何在迭代器遍历的过程中,一旦发现这个对象的mcount和迭代器中存储的mcount不一样那就抛异常

面试题3. HashMap在高并发下如果没有处理线程安全会有怎样的安全隐患,具体表现是什么

  1. 在高并发情况下有可能会形成循环链表,具体表现为CPU的使用率达到100%
  2. 还有一个中可能是因为如果两个线程同时进行对一个节点记性put的时候,可能会出现最后一个put操作会覆盖第一个put的数据。

面试题4. hashmap和treemap时间复杂度。

首先TreeMap是继承了AbstractMap实现了SortMap的接口,在构造TreeMap的时候都是直接传入的是Comparator对象,如果不是的话,就使用默认key的Comparable接口(实现自然排序)

  1. HashMap的时间复杂度为O(1)
  2. 而TreeMap的时间复杂度为O(logN),因为TreeMap的底层是用红黑树来实现的,但是他的key不能为null值,也不可以重复(重复则覆盖),主要一般使用TreeMap来进行一些排序功能

面试题5. linkedList与arrayList区别 适用场景

面试题6. Arraylist是如何扩容的(默认数组大小是10)?

  1. 首先当你执行add()方法的时候,会先调用这个方法ensureCapacityInternal()来确保数组的容量够用,然后会继续在这个方法中调用ensureExplicitCapacity(alculateCapacity(elementData, minCapacity))中的alculateCapacity(elementData, minCapacity)方法来进行比较出是ArrayList中的默认容量和自己初始化的容量那个更大,返回最大的那个作为最后数组的容量
  2. 把上一个获得的最终数组最大的容量传给ensureExplicitCapacity(上一步中最大的值max),然后进行判断如果这个最大的值大于数组中的元素的长度的话,就说明数组的容量不够存储这个数组的元素的大小,然后进行扩容grow()
  3. 在grow()方法中,先进行对之前的数组容量进行1.5倍扩容,然后判断如果扩容1.5倍后的大小仍然小于之前数组最终那次初始化的容量大小时,说明按此初始化的数组容量大小仍然可以满足,直接把扩容后的数组大小还是初始化的那个,依然不变,
  4. 如果扩容后的新数组大小大于Integer-8的值的话,反正不能超过Integer的范围,最后直接调用Arrays.copyOf()方法进行复制数组。
    

面试题7. hashset和hashmap的区别?

  1. HashSet其实底层的构造就是使用的是HashMap来进行实现的,但是还是会有些不一样的地反
  2. 第一个是HashSet不允许元素重复,就算如果元素重复的话,也不会去覆盖之前重复的元素。
  3. 还有一点就是在HashSet中存储的是对象的话,最好需要重写equals方法和hashCode方法,以保证放入Set对象的唯一性
  4. HashSet不提供get()方法,而且因为set内部是无序的,所以只能通过迭代器进行遍历。

面试题8. JDK1.7和JDK1.8的ConcurrentHashMap的区别?

  1. 结构上:JDK1.7中的时候ConcurrentHashMap采用了数组+Segment+分段锁的方式实现。而1.8使用的是数组+CAS+红黑树/链表来进行实现的。
  2. 保证线程安全的锁机制上:JDK1.7采用segment的分段锁机制实现线程安全,其中segment继承自ReentrantLock。JDK1.8采用CAS+Synchronized保证线程安全。
  3. 锁的粒度:原来是对需要进行数据操作的Segment加锁,现调整为对每个数组元素加锁(Node)。
  4. 链表转化为红黑树:定位结点的hash算法简化会带来弊端,Hash冲突加剧,因此在链表节点数量大于8时,会将链表转化为红黑树进行存储。
  5. 查询时间复杂度:从原来的遍历链表O(n),变成遍历红黑树O(logN)。

面试题9. java容器类的层次结构,分别讲一下各种容器的原理,LinkedList的删除操作怎么实现;TreeSet的add操作怎么实现的,详细一点;LinkedHashMap实现机制,如何保证添加元素的有序性。

面试题10. 在hashmap做put的时候是怎么做hash的以及为什么容量是2的n次方

面试题11. 让你设计个lru,你会考虑哪些因素,具体怎么做(答:容量还有热点数据.然后面试官还补充了搜索,我说用linkedhashmap做,然后说了下怎么实现,他说还有什么其他方式么?linkedlist hashmap)

面试题12. Currenthashmap工作原理?

面试题13. 有哪些集合类实现了Map接口?

面试题14. HashMap如果空间利用率不高,怎么改进

面试题15. hashmap,treemap之间的区别?

面试题16. HashSet和TreeSet的区别?

HashSet底层其实相当于是包了一层HashMap,但是又不同于HashMap,不仅不提供get()方法,因为它是基于hash表的这样一种数据结构,在查询和删除快,添加比较慢,因为它是根据存进来的对象的hashcode来进行定位数据,所以如果是添加对象的话,一般建议需要进行重写hashCode()和equals()方法。

  1. 第一个他的特点就是存储的数据都是无序的
  2. 第二个就是他存储的数据不能重复,因为它是靠对象的hashCode()方法和equals()方法来进行区分重复数据的

而TreeSet的底层其实是包了一层TreeMap的,他之所以能进行对数据的排序是因为他的底层是使用了二叉树(这样的话,当他的数据越多树的高度越高效率就越低)

  1. TreeSet的特点就是他可以进行排序数据,因为他是基于Comparable接口来进行区分重复的数据的
  2. 他是基于树的数据结构的,所以他的查询删除、containsValue()的时间复杂度都是O(logN)

猜你喜欢

转载自blog.csdn.net/qq_36520235/article/details/86745780