Java集合面试题

1.常见的集合有哪些?

List 列表,有序,可重复;
Queue 队列,有序,可重复;
Set 集合,不可重复;
Map 映射,无序,键唯一,值不唯一;
每种集合类型下都包含多个具体的实现类。

2.List 、Set和Map 的区别

List和Set是存储单列数据的集合,Map是存储键值对这样的双列数据的集合;
List中存储的数据是有顺序的,并且值允许重复;Map中存储的数据是无序的,它的键是不允许重复的,但是值是允许重复的;Set中存储的数据是无顺序的,并且不允许重复,但元素在集合中的位置是由元素的hashcode决定,即位置是固定的(Set集合是根据hashcode来进行数据存储的,所以位置是固定的,但是这个位置不是用户可以控制的,所以对于用户来说set中的元素还是无序的)。

3.ArrayList了解吗?

Java 集合框架拥有两大接口 Collection 和 Map,其中,Collection 麾下三生子 List、Set 和 Queue。ArrayList 就实现了 List 接口,其实就是一个数组列表,不过作为 Java 的集合框架,它只能存储对象引用类型,也就是说当我们需要装载的数据是诸如 int、float 等基本数据类型的时候,必须把它们转换成对应的包装类。

4.ArrayList 的扩容机制?

扩容机制
JDK1.8
底层使用数组实现,默认初始容量为10. 当超出后,会自动扩容为原来的1.5倍,即自动扩容机制。 数组的扩容是新建一个大容量(原始数组大小+扩充容量)的数组,然后将原始数组 数据拷贝到新数组,然后将新数组作为扩容之后的数组。数组扩容的操作代价很高,我们应该尽量减少这种操作。

5.Arraylist和 Vector 的区别

  • ArrayList 是 List 的主要实现类,底层使用 Object[]存储,适用于频繁的查找工作,线程不安全 ;
  • Vector 是 List 的古老实现类,底层使用Object[] 存储,线程安全的。

6.Arraylist 与 LinkedList 区别

  1. **是否保证线程安全:**ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
  2. **底层数据结构:**Arraylist 底层使用的是 Object 数组;LinkedList 底层使用的是 双向链表 数据结构(JDK1.6 之前为循环链表,JDK1.7 取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)
  3. 插入和删除是否受元素位置的影响:ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是 O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element))时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② LinkedList 采用链表存储,所以对于add(E e)方法的插入,删除元素时间复杂度不受元素位置的影响,近似 O(1),如果是要在指定位置i插入和删除元素的话((add(int index, E element)) 时间复杂度近似为o(n))因为需要先移动到指定位置再插入。
  4. **是否支持快速随机访问:**LinkedList 不支持高效的随机元素访问,而 ArrayList 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。
  5. **内存空间占用:**ArrayList 的空 间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)。

7.HashMap

7.1 解决hash冲突的办法有哪些? HashMap用的哪种?

开放定址法就是解决hash冲突的一种方式。它是使用一种 探测方式在整个数组中找到另一个可以存 储值的地方。
链地址法(拉链法)HashMap,HashSet其实都是采用的拉链法来解决哈希冲突的,就是在每个位桶 实现的时候,我们采用链表(jdk1.8之后采用链表+红黑树)的数据结构来去存取发生哈希冲突的输 入域的关键字
再散列法再散列法其实很简单,就是再使用哈希函数去散列一个输入的时候,输出是同一个位置就 再次散列,直至不发生冲突位置
缺点:每次冲突都要重新散列,计算时间增加

7.2 使用的hash算法?

image.png

7.3 扩容过程?

JDK 1.7 中整个扩容过程就是一个取出数组元素(实际数组索引位置上的每个元素是每个独立单向链表的头部,也就是发生 Hash 冲突后最后放入的冲突元素)然后遍历以该元素为头的单向链表元素,依据每个被遍历元素的 hash 值计算其在新数组中的下标然后进行交换(即原来 hash 冲突的单向链表尾部变成了扩容后单向链表的头部)。
在 JDK 1.8 中 HashMap 的扩容操作就显得更加的骚气了, 由于扩容数组的长度是 2 倍关系,所以对于假设初始 tableSize = 4 要扩容到 8 来说就是 0100 到 1000 的变化 (左移一位就是 2 倍),在扩容中只用判断原来的 hash 值 与左移动的一位(newtable 的值)按位与操作是 0 或 1 就 行,0 的话索引就不变,1 的话索引变成原索引加上扩容前数组的长度。

7.4 put方法流程?

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

想进阿里的小菜鸡

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

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

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

打赏作者

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

抵扣说明:

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

余额充值