面试--集合

简介: 面试--集合

☺ 集合重点---HashMap

可以看一下文章《从HashMap的执行流程开始 揭开HashMap底层实现


一、集合

1、说说List、Set、Map三者的区别?

谈及元素的有序性、重复性,Map的键值对结构


答:List 存储的元素是有序的,可以重复的;而 Set 存储的元素是无序的,不可以重复的;

Map 是以 key-value 键值对结构存储元素,key 是无序的,不可以重复的,value也是无序,但是可以重复。


2、ArrayList与 LinkedList 异同点?

谈及底层数据结构、元素是否支持随机访问(访问速度)、元素的插入和删除速度(当然还可以谈及线程安全、内存占用这些)


答:ArrayList与 LinkedList 都是List 接口的实现类,但是底层实现不同。ArrayList 底层数据结构是 Object动态数组,而LikedList是使用双向链表

ArrayList 支持元素的随机访问,且访问速度优于LinkedList,因为ArrayList 是直接通过数组下标查找到元素,LinkedList 则需要移动指针遍历每个元素,直到找到元素。

插入和删除元素,LinkedList 速度反而比ArrayList快,因为插入和删除元素,对于数组需要需要移动数组中插入或删除位置之后的的所有元素。

所以,频繁使用查询操作,优先选择ArrayList,频繁增删的使用LinkedList。


3、ArrayList 与 Vector 区别呢? 为什么要⽤Arraylist取代 Vector呢?

区别谈及线程安全、扩容倍数;取代:同步(synchronized)


答:区别:ArrayList 是线程不安全的,Vector 是线程安全的;当容量不足时,Vector 默认增长为原来的两倍,而 ArrayList 的增长为原

来的1.5倍。

取代:Vector类的所有方法都是同步的(synchronized),但是,如果你只用单线程来访问Vector对象,那么你的代码将会在同步操作上浪费相当多的时间。


4、⽐较 HashSet、LinkedHashSet 和 TreeSet 三者的异同?

谈及底层数据结构、继承关系、线程安全、有序性


答:HashSet 是 Set 接⼝的主要实现类,HashSet 的底层是 HashMap,线程不安全的,可以存储 null 值;

LinkedHashSet 是 HashSet 的⼦类,能够按照添加的顺序遍历;

TreeSet 底层使⽤红⿊树,能够按照添加元素的顺序进⾏遍历,排序的⽅式有⾃然排序和定制排序;



二、集合重点---HashMap

1、HashMap加载因子为什么是0.75?

谈及扩容、哈希冲突


答:加载因子小于 0.75,会导致频繁扩容,而大于 0.75,导致 哈希冲突概论增大

因为加载因子设置比较大的时候,扩容的门槛就被提高了,扩容发生的频率比较低,占用的空间会比较小,但此时发生 Hash冲突的几率就会提升


2、HashMap的底层数据结构是什么?

谈及引入红黑树的目的(时间复杂度)


答:jdk7 底层数据结构是数组+链表;jdk8 底层数据结构是数组+链表+红黑树;

当链表过长,则会严重影响 HashMap 的性能,红黑树搜索时间复杂度是 O(logn),而链表是的 O(n)。因此,JDK1.8 对数据结构做了进一步的优化,引入了红黑树,链表和红黑树在达到一定条件会进行转换:当链表的结点大于8且数组容量大于64,单链表转成红黑树


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


答:解决哈希冲突方法:开放定址法、再哈希法、链地址法(拉链法)。其中HashMap用的链地址法,使用链表+红黑树


4、为什么在解决 hash 冲突的时候,不直接用红黑树?而 选择先用链表,再转红黑树?

谈及红黑树的旋转、变色,元素个数小于8,链表可以保证性能;大于8,时间复杂度对比,使用红黑树的缺点:薪增节点效率变慢


答:因为红黑树需要进行左旋,右旋,变色这些操作来保持平衡,而单链表不需要。当元素小于 8 个的时候,此时做查询操作,链表结构已经能保证查询性能。当元素大于 8 个的时候, 红黑树搜索时间复杂度是 O(logn),而链表是 O(n),此时需要红黑树来加快查询速度,但是新增节点的效率变慢了

因此,如果一开始就用红黑树结构,元素太少,新增效率又比较慢,无疑这是浪费性能的。


5、HashMap 中 key 的存储索引是怎么计算的?


答: ① 生成key的哈希值 ② 高位参与运算 ③ 取模运算

  • 高位参与运算:将哈希值低16位与高16 位进行混合,企图让哈希值分布更加均匀
  • 取模运算:定位到数组的索引位置


6、一般用什么作为HashMap的key?


答:一般用Integer、String 这种不可变类当 HashMap 当 key,而且 String 最为常用

因为字符串是不可变的,所以在它创建的时候 hashcode 就被缓存了,不需要重新计算。这就是 HashMap 中的键往往都使用字符串的原因。


7、HashMap的容量为什么要设置为2 的次幂?

谈及高位运算


答:HashMap采用这种非 常规设计(常规是设计成素数),主要是为了在取模和扩容时做优化,同时为了减少冲突,HashMap定位哈希桶索引位置时,也加入了高位参与运算的过程。


8、JDK1.8中的HashMap为什么用红黑树不用普通的AVL树?

谈及红黑树和AVL树的区别


答:红黑树整体来说性能要优于AVL树,红黑树牺牲了部分平衡性以换取插入/删除操作时少量的旋转操作。

在时间复杂度方面,avl树和红黑树一样,搜索、添加、删除 都是 O(logn),但是两者旋转调整次数是不同

avl树:添加仅需 O(1) 次旋转调整、删除最多需要 O(logn) 次旋转调整;红黑树:添加、删除都 O(1) 次旋转调整


9、HashMap 的put流程?

总结put时的思考点:

1、哈希表是否为空判断---空(需要扩容)

2、定位哈希表索引对应的元素是否为空判断---空(直接插入)

3、元素非空,判断key是否存在,存在直接覆盖

不存在,判断该节点是否是一颗树节点,是树节点->红黑树插入

不是树节点->链表插入,插入后判断节点数量是否大于8,大于8树化成红黑树

4、插入元素后判断是否大于 threshold(可以容纳的最大元素数目/节点数) --大于(需要扩容)


10、扩容?

扩容时,扩容是从一个数组拷贝到另外一个数组。

当向容器添加元素的时候,会判断当前容器的元素个数,如果大于等于阈值, 即当前数组的长度乘以加载因子的值的时候,就要自动扩容啦。

当然 Java 里的数组是无法自动扩容的,方法 是使 用一个新的数组代替已有的容量小的数组。

当HashMap中的其中一个链表的对象个数如果达到了8个,此时如果数组长度没有达到64,那么HashMap会先扩容解决,如果已经达到了64,那么这个链表会变成红黑树,结点类型由Node变成TreeNode类型。当然,如果映射关系被移除后,下次执行resize方法时判断树的结点个数低于6,也会再把树转换为链表。


11、HashMap 的工作原理是什么?

HashMap 是以键值对 (key-value) 的形式存储元素的。HashMap 需要 一个 hash 函数,它使用 hashCode()和 equals()方法来向集合添加和检索元素。当调用 put() 方法的时候,HashMap 会计算 key 的 hash 值,然后把键 值对存储在集合中合适的索引上。

如果 key 已经存在了,value 会被更新成新值

HashMap 的一些重要的特性是它的容量 (capacity),负载因子 (load factor) 和 扩容极限(threshold resizing)。


12、HashMap 是线程安全的吗,为什么不是线程安全的?怎么解决?


答:不是线程安全的;

插入元素时,

如果有两个线程A和B,都进行插入数据,刚好这两条不同的数据经过哈希计算后得到的哈希码是一样的,且该位置还没有其他的数据。

假设一种情况,线程A通过if判断,该位置没有哈希冲突,进入了if语句还没有进行数据插入

这时候 CPU 就把资源让给了线程B,线程A停在了if语句里面

线程B判断该位置没有哈希冲突(线程A的数据还没插入),也进入了if 语句,线程B执行完后,轮到线程A执行,这时候,你会发现线程A把线程B插入的数据给覆盖了。发生了线程不安全情况

本来在 HashMap 中,发生哈希冲突是可以用链表法或者红黑树来解决的,但是在多线程中,可能就直接给覆盖了

解决:使用ConcurrentHashMap。


接下来需要了解ConcurrentHashMap。



如果本文对你有帮助的话记得给一乐点个赞哦,感谢!

目录
相关文章
|
6月前
|
存储 安全 算法
Java 集合面试题 PDF 下载及高频考点解析
本文围绕Java集合面试题展开,详细解析了集合框架的基本概念、常见集合类的特点与应用场景。内容涵盖`ArrayList`与`LinkedList`的区别、`HashSet`与`TreeSet`的对比、`HashMap`与`ConcurrentHashMap`的线程安全性分析等。通过技术方案与应用实例,帮助读者深入理解集合类的特性和使用场景,提升解决实际开发问题的能力。文末附带资源链接,供进一步学习参考。
159 4
|
6月前
|
存储 安全 Java
Java 集合面试题从数据结构到 HashMap 源码剖析详解及长尾考点梳理
本文深入解析Java集合框架,涵盖基础概念、常见集合类型及HashMap的底层数据结构与源码实现。从Collection、Map到Iterator接口,逐一剖析其特性与应用场景。重点解读HashMap在JDK1.7与1.8中的数据结构演变,包括数组+链表+红黑树优化,以及put方法和扩容机制的实现细节。结合订单管理与用户权限管理等实际案例,展示集合框架的应用价值,助你全面掌握相关知识,轻松应对面试与开发需求。
332 3
|
安全 Java 容器
【Java集合类面试二十七】、谈谈CopyOnWriteArrayList的原理
CopyOnWriteArrayList是一种线程安全的ArrayList,通过在写操作时复制新数组来保证线程安全,适用于读多写少的场景,但可能因内存占用和无法保证实时性而有性能问题。
|
存储 安全 Java
【Java集合类面试二十五】、有哪些线程安全的List?
线程安全的List包括Vector、Collections.SynchronizedList和CopyOnWriteArrayList,其中CopyOnWriteArrayList通过复制底层数组实现写操作,提供了最优的线程安全性能。
【Java集合类面试二十八】、说一说TreeSet和HashSet的区别
HashSet基于哈希表实现,无序且可以有一个null元素;TreeSet基于红黑树实现,支持排序,不允许null元素。
【Java集合类面试二十三】、List和Set有什么区别?
List和Set的主要区别在于List是一个有序且允许元素重复的集合,而Set是一个无序且元素不重复的集合。
【Java集合类面试二十六】、介绍一下ArrayList的数据结构?
ArrayList是基于可动态扩展的数组实现的,支持快速随机访问,但在插入和删除操作时可能需要数组复制而性能较差。
|
存储 Java 索引
【Java集合类面试二十四】、ArrayList和LinkedList有什么区别?
ArrayList基于动态数组实现,支持快速随机访问;LinkedList基于双向链表实现,插入和删除操作更高效,但占用更多内存。
|
存储 安全 算法
Java面试题之Java集合面试题 50道(带答案)
这篇文章提供了50道Java集合框架的面试题及其答案,涵盖了集合的基础知识、底层数据结构、不同集合类的特点和用法,以及一些高级主题如并发集合的使用。
1250 1
Java面试题之Java集合面试题 50道(带答案)
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)