速记Java八股文——集合篇

前言

分类汇总 10+ 常见的 Java集合 经典后端面试题,并对题目进行了精炼总结,旨在帮助大家高效记忆,在面试中游刃有余,不至于陷入词穷的窘境。

Java 集合


什么是 Java 集合?

集合是存储多个元素的容器,长度可变,存储元素可能是引用类型,可以存储多种类型对象。


请你说一下集合体系,从顶层说起

Java 集合可分为三大类:单列值集合Collection、键值对双列集合Map、工具类。

Collection 接口

  • List 接口:有序集合,允许重复元素。

    • ArrayList:基于动态数组实现。

    • LinkedList:基于双向链表实现。

    • Vector:线程安全的动态数组实现。

  • Set 接口:无序集合,不允许重复元素。

    • HashSet:基于哈希表实现。

    • LinkedHashSet:基于哈希表和双向链表实现,保持插入顺序。

    • TreeSet:基于红黑树实现,元素有序。

  • Queue 接口:队列,先进先出(FIFO)。

    • LinkedList:也实现 Queue 接口。

    • PriorityQueue:优先队列,基于堆实现。

Map 接口:键值对集合,键唯一,值可以重复。

  • HashMap:基于哈希表实现。

  • LinkedHashMap:基于哈希表和双向链表实现,保持插入顺序。

  • TreeMap:基于红黑树实现,键有序。

  • Hashtable:线程安全的哈希表实现。

工具类Collections

  • sort(List< T > list): 对列表进行自然排序。

  • synchronizedList(List< T > list):返回线程安全的列表。

  • reverse(List<?> list):反转列表中的元素顺序。

  • max(Collection<? extends T> coll):根据元素的自然顺序返回集合中的最大元素。


List() 和 Iterate() 的区别?

  • List:是一个集合接口,提供基于索引的访问和操作元素的方法。

  • Iterator:是一个遍历接口,提供统一的方式来遍历集合元素,不依赖于集合的具体实现。


LinkedList和ArrayList有什么区别?

  • LinkedList: 双向链表,查询慢O(n),增删快O(1),内存占用较多,每个元素需额外存储前后引用。线程不安全。适用于频繁插入删除的场景。

  • ArrayList:动态数组,查询快O(1),增删快O(n),内存占用较少,扩容有额外开销。线程不安全。适用于随机访问和尾部操作的场景。


什么是数组越界?

数组越界是指在访问数组元素时,索引超出了数组的合法范围(即小于0或大于等于数组长度)。


简称 HashMap 和 HashSet 的区别?

  • HashMap:基于哈希表的键值对存储,实现Map接口,键唯一,值可重复。内部使用数组和链表(或红黑树)实现。

  • HashSet:基于哈希表的集合存储,实现 Set 接口,存储唯一元素,不允许重复。内部使用HashMap实现,元素作为HashMap的键。


HashSet 如何检查重复?

HashSet 通过计算元素的 hashCode() 确定存储位置,遍历该位置的链表或(红黑树),使用 equals() 方法检查重复元素,确保集合汇总元素唯一。


HashSet 和 TreeSet 的区别?

HashSet:基于哈希表实现,内部使用HashMap。无序。插入、删除和查找操作平均时间复杂度为O(1)。
TreeSet: 基于红黑树实现,内部使用TreeMap。有序,默认按自然顺序或通过比较器 Comparator 排序。插入、删除和查找操作平均时间复杂度为O(n)。


HashMap和HashTable的区别,哪个的性能更好?

  • HashMap: 继承自 AbstractMap 类,实现 Map接口。允许一个键为null,允许多个值为null。使用 Enumeration 进行迭代。默认初始容量为 11,扩容时容量变为原来的 2 倍加 1。非线程安全,没有同步机制,性能更好。

  • HashTable: 继承自 Dictionary 类。不允许键值对为null。使用 Iterator 进行迭代,支持 fail-fast 机制。默认初始容量为 16,扩容时容量变为原来的 2 倍。线程安全,所有方法都是同步的(使用 synchronized 关键字)。


HashMap的底层原理是什么?

HashMap 的底层原理基于哈希表。JDK1.8 前,底层采用数组+链表,使用的是头插法。
JDK1.8后,底层采用数组+链表+红黑树,使用的是尾插法,红黑树优化了链表过长的问题。当链表长度超过阈值(默认为8),链表会转换为红黑树。当红黑树节点数量减少到一定阈值(默认为 6),红黑树会转换回链表。


HashMap 和 ConcurrentHashMap 的区别?

  • HashMap是非线程安全的。ConcurrentHashMap是线程安全的。

  • HashMap是无锁机制。ConcurrentHashMap采用锁分段机制(Java 8 之前)或基于CAS操作(Java 8 及以后),减少锁的粒度,提高并发性能。

  • HashMap允许一个键为null,允许多个值为null。ConcurrentHashMap不允许键或值为空。

  • HashMap:迭代器在检测到结构变化时会抛出 ConcurrentModificationException,是 fail-fast 的。 ConcurrentHashMap 迭代器是弱一致性的,可以在迭代过程中看到其他线程的部分更新,不会抛出 ConcurrentModificationException。


讲一下HaspMap的扩容机制

  • HashMap的默认初始容量为16,默认加载因子为0.75,默认阈值达到12。

  • 当 HashMap 中的元素数量超过 容量 * 负载 因子 时,触发扩容。

  • 扩容时,将当前数组容量翻倍,即新的容量是原来的两倍。

  • 扩容后,并将原有元素重新散列到新的更大的数组中。

  • 在JDK8中,为了优化性能,当哈希表的大小小于64时,负载因子为0.5,而不是默认值0.75。

ConcurrentHashMap各版本的变化

  1. JDK1.5: 引入ConcurrentHashMap,不支持扩容。使用分段锁(Segment)实现。
  2. JDK1.6:对扩容机制进行了优化。当有线程正在扩容时,其他线程可以继续读取原来的数据结构,从而减少了整个表被锁定的时间。
  3. JDK1.7:不再使用Segment,而是采用了CAS和synchronized来保证线程安全性。链表结构改为了红黑树结构,增加了对Map.Entry的支持。还添加了一个ConcurrentHashMap.reduceEntries()方法,可以对哈希表中的所有键值对进行并行操作。
  4. JDK1.8:使用了CAS操作来保证线程安全性,还添加了ConcurrentHashMap.mappingCount()方法,用于返回当前映射表中的键值对数量。
  • 21
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值