备战金九银十的50道刷题Java集合经典面试题

1. Arraylist与LinkedList区别

可以从它们的底层数据结构、效率、开销进行阐述哈

  • ArrayList是数组的数据结构,LinkedList是链表的数据结构。

  • 随机访问的时候,ArrayList的效率比较高,因为LinkedList要移动指针,而ArrayList是基于索引(index)的数据结构,可以直接映射到。

  • 插入、删除数据时,LinkedList的效率比较高,因为ArrayList要移动数据。

  • LinkedList比ArrayList开销更大,因为LinkedList的节点除了存储数据,还需要存储引用。

2. Collections.sort和Arrays.sort的实现原理

Collection.sort是对list进行排序,Arrays.sort是对数组进行排序。

Collections.sort底层实现

Collections.sort方法调用了list.sort方法

list.sort方法调用了Arrays.sort的方法

因此,Collections.sort方法底层就是调用的Array.sort方法

Arrays.sort底层实现

Arrays的sort方法,如下:

如果比较器为null,进入sort(a)方法。如下:

因此,Arrays的sort方法底层就是:

  • legacyMergeSort(a),归并排序,

  • ComparableTimSort.sort():即Timsort排序。

Timesort排序

Timsort排序是结合了合并排序(merge.sort)和插入排序(insertion sort)而得出的排序方法;

1.当数组长度小于某个值,采用的是二分插入排序算法,如下:

 

找到各个run,并入栈。 

按规则合并run。 

3. HashMap原理,java8做了什么改变

  • HashMap是以键值对存储数据的集合容器

  • HashMap是非线性安全的。

  • HashMap底层数据结构:数组+(链表、红黑树),jdk8之前是用数组+链表的方式实现,jdk8引进了红黑树

  • Hashmap数组的默认初始长度是16,key和value都允许null的存在

  • HashMap的内部实现数组是Node[]数组,上面存放的是key-value键值对的节点。HashMap通过put和get方法存储和获取。

  • HashMap的put方法,首先计算key的hashcode值,定位到对应的数组索引,然后再在该索引的单向链表上进行循环遍历,用equals比较key是否存在,如果存在则用新的value覆盖原值,如果没有则向后追加。

  • jdk8中put方法:先判断Hashmap是否为空,为空就扩容,不为空计算出key的hash值i,然后看table[i]是否为空,为空就直接插入,不为空判断当前位置的key和table[i]是否相同,相同就覆盖,不相同就查看table[i]是否是红黑树节点,如果是的话就用红黑树直接插入键值对,如果不是开始遍历链表插入,如果遇到重复值就覆盖,否则直接插入,如果链表长度大于8,转为红黑树结构,执行完成后看size是否大于阈值threshold,大于就扩容,否则直接结束。

  • Hashmap解决hash冲突,使用的是链地址法,即数组+链表的形式来解决。put执行首先判断table[i]位置,如果为空就直接插入,不为空判断和当前值是否相等,相等就覆盖,如果不相等的话,判断是否是红黑树节点,如果不是,就从table[i]位置开始遍历链表,相等覆盖,不相等插入。

  • HashMap的get方法就是计算出要获取元素的hash值,去对应位置获取即可。

  • HashMap的扩容机制,Hashmap的扩容中主要进行两步,第一步把数组长度变为原来的两倍,第二部把旧数组的元素重新计算hash插入到新数组中,jdk8时,不用重新计算hash,只用看看原来的hash值新增的一位是零还是1,如果是1这个元素在新数组中的位置,是原数组的位置加原数组长度,如果是零就插入到原数组中。扩容过程第二部一个非常重要的方法是transfer方法,采用头插法,把旧数组的元素插入到新数组中。

  • HashMap大小为什么是2的幂次方?效率高+空间分布均匀

有关于HashMap这些常量设计目的,也可以看我这篇文章:

面试加分项-HashMap源码中这些常量的设计目的

4. List 和 Set,Map 的区别

  • List 以索引来存取元素,有序的,元素是允许重复的,可以插入多个null。

  • Set 不能存放重复元素,无序的,只允许一个null

  • Map 保存键值对映射,映射关系可以一对一、多对一

  • List 有基于数组、链表实现两种方式

  • Set、Map 容器有基于哈希存储和红黑树两种方式实现

  • Set 基于 Map 实现,Set 里的元素值就是 Map的键值

5. poll()方法和 remove()方法的区别?

Queue队列中,poll() 和 remove() 都是从队列中取出一个元素,在队列元素为空的情况下,remove() 方法会抛出异常,poll() 方法只会返回 null 。

看一下源码的解释吧:

/**
     * Retrieves and removes the head of this queue.  This method differs
     * from {@link #poll poll} only in that it throws an exception if this
     * queue is empty.
     *
     * @return the head of this queue
     * @throws NoSuchElementException if this queue is empty
     */
    E remove();

/**
     * Retrieves and removes the head of this queue,
     * or returns {@code null} if this queue is empty.
     *
     * @return the head of this queue, or {@code null} if this queue is empty
     */
E poll();

6. HashMap,HashTable,ConcurrentHash的共同点和区别

HashMap

  • 底层由链表+数组+红黑树实现

  • 可以存储null键和null值

  • 线性不安全

  • 初始容量为16,扩容每次都是2的n次幂

  • 加载因子为0.75,当Map中元素总数超过Entry数组的0.75,触发扩容操作.

  • 并发情况下,HashMap进行put操作会引起死循环,导致CPU利用率接近100%

  • HashMap是对Map接口的实现

HashTable

  • HashTable的底层也是由链表+数组+红黑树实现。

  • 无论key还是value都不能为null

  • 它是线性安全的,使用了synchronized关键字。

  • HashTable实现了Map接口和Dictionary抽象类

  • Hashtable初始容量为11

ConcurrentHashMap

  • ConcurrentHashMap的底层是数组+链表+红黑树

  • 不能存储null键和值

  • ConcurrentHashMap是线程安全的

  • ConcurrentHashMap使用锁分段技术确保线性安全

  • JDK8为何又放弃分段锁,是因为多个分段锁浪费内存空间,竞争同一个锁的概率非常小,分段锁反而会造成效率低。

7. 写一段代码在遍历 ArrayList 时移除一个元素

因为foreach删除会导致快速失败问题,fori顺序遍历会导致重复元素没删除,所以正确解法如下:

第一种遍历,倒叙遍历删除

for(int i=list.size()-1; i>-1; i--){
  if(list.get(i).equals("jay")){
    list.remove(list.get(i));
  }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倾听铃的声

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值