java基础面试题(十五)

  1. 为什么HashMap的数据结构要在JDK1.8后加上红黑树?
    答:优化时间复杂度,提高搜索效率。假设HashMap大量元素的hashCode是相等的,都存放在了一个桶中,这个桶下就会拉出一个长长的链表,这时候的hashMap就相当于是一个链表,搜索的时间复杂度是o(n),链表数据越多,查询效率越低。所以加入了红黑树,在链表下的元素数目大于等于某个指定值,结构就会从链表转为红黑树,这时搜索的时间复杂度为O(logn),优化了搜索效率,而一旦链表下的元素数目小于某个指定值,就会再从红黑树转回链表,最大程度的保证了效率。

  2. Iterator 和 ListIterator 有什么区别?
    答:ListIterator实现了Iterator接口,多了些自己的方法。但是相比于Iterator可以遍历Set和List,ListIterator只能遍历List。同时Iterator对集合只能前向遍历,而ListIterator既能前向也能后向。

  3. 快速失败(fail-fast)和安全失败(fail-safe)的区别是什么?
    答:这里需要结合并发场景来做个说明,当迭代器在遍历集合时,如果有另一个线程对集合对象内容做了修改,会抛出Concurrent Modification Exception异常的就是快速失败(fail-fast),而不会受影响,能继续正常遍历的就是安全失败(fail-safe)。java.util包下的集合类都是快速失败的,java.util.concurrent包下的容器都是安全失败。

  4. 快速失败(fail-fast)的原理?
    答:集合内部维护了一个modCount变量,初始值为0,同时迭代器内部还有个expectedModCount变量,在创建迭代器的时候会把对象的modCount的值传递给迭代器的expectedModCount,每当集合的内容有变化时,也可以理解成我们对集合做了修改时,modCount值就会做自增操作。然后在迭代器调用hasNext()和Next()方法时,就会去检查modCount的值是否等于expectedModCount的值,不等于就抛出异常,终止遍历。

  5. 说说迭代器的expectedModCount变量的作用?
    答:这个变量其实就是保证了在使用迭代器时,集合的修改有且只能通过这一个迭代器来进行。要知道如果多线程情况下对集合进行迭代,那么就会创建多个迭代器,会出现一个modCount对多个expectedModCount的场景,这样modCount的值和expectedModCount的值就会出现不等,就通过不了校验,会抛出异常。校验方法源码如下:
    在这里插入图片描述

  6. java.util.concurrent包下的容器是怎么做到安全失败(fail-safe)的?
    答:其实java.util.concurrent包下的容器就是在迭代时对原有的集合做拷贝,然后对拷贝的集合做遍历,这样就算是修改原有的集合内容,也不会对拷贝的集合遍历产生影响,也就不会抛出Concurrent Modification Exception异常了。

  7. ConcurrentHashMap和Hashtable有什么区别?
    答:首先两者都是线程安全的。不过Hashtable是采用在方法上加锁的方式来做到线程同步,而ConcurrentHashMap则是减小了锁粒度,采用了分段锁,相比起来ConcurrentHashMap的并发能力强很多,可以替代Hashtable使用。

  8. 数组(Array)和列表(ArrayList)有什么区别?
    答:Array可以包含基本类型和对象,而ArrayList只能包含对象。Array在使用时就初始化了大小,长度是固定的,而ArrayList可以做到自动扩容,长度是不固定的。ArrayList提供了更多的方法和特性,所以操作起来更灵活。

  9. 数组(Array)如何转列表(ArrayList),列表(ArrayList)如何转数组(Array)?
    答:数组(Array)转列表(ArrayList)使用的是数组的工具类Arrays的静态方法asList
    列表(ArrayList)转数组(Array)使用的是集合的方法toArray

  10. 如何将集合打乱?
    答:使用Collections.shuffle(list)方法就能够打乱集合满足奇葩需求。

发布了166 篇原创文章 · 获赞 155 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_38106322/article/details/104224861