Java 集合面试题

引用:(代码随想录的八股转免费了)以下为网址

卡码笔记

本文为学习以上文章的笔记,如果有时间推荐直接去原网址

Sting 导图

List导图

ArrayList 和 Array 有什么区别?ArrayList 和 LinkedList 的区别是什么?(考点:底层数据结构、性能差异)【简单】

ArrayList 和 Array 的区别:

  1. 类型
    • Array 是Java中的一个基本数据结构,可以存储基本类型数据或对象引用。
    • ArrayList 是Java集合框架中的一个类,实现了List接口,只能存储对象引用。
  2. 大小可变性
    • Array 的大小在创建时确定,一旦创建就无法改变。
    • ArrayList 的大小是动态的,可以根据需要自动扩容。
  3. 性能
    • 访问元素时,Array 通常比 ArrayList 快,因为 Array 直接通过索引访问。
    • ArrayList 在添加或删除元素时可能更高效,尤其是在数组末尾操作时。
  4. 泛型支持
    • Array 可以是泛型的,也可以不是。
    • ArrayList 必须是泛型的,提供了类型安全。
  5. 方法
    • Array 提供的操作比较有限,主要是基本的数据访问和修改。
    • ArrayList 提供了更多的方法,如添加、删除、迭代等。

ArrayList 和 LinkedList 的区别:

  1. 数据结构
    • ArrayList 是基于动态数组实现的,适合随机访问。
    • LinkedList 是基于双向链表实现的,适合插入和删除操作。
  2. 性能
    • ArrayList 在随机访问元素时更快,因为它是通过索引直接访问。
    • LinkedList 在插入和删除元素时更快,因为它不需要移动其他元素。
  3. 内存占用
    • ArrayList 由于是基于数组,它在存储大量元素时可能会更高效。
    • LinkedList 每个元素都需要额外的内存空间来存储前驱和后继元素的引用。
  4. 扩容
    • ArrayList 在元素数量达到容量时需要扩容,这个过程涉及到创建新数组和复制旧数组元素。
    • LinkedList 不需要扩容,因为它通过链接节点来增加元素。
  5. 功能
    • ArrayList 提供了更快的随机访问和更高效的内存使用。
    • LinkedList 提供了更高效的插入和删除操作,并且可以更有效地实现栈和队列等数据结构。

在选择ArrayList还是LinkedList时,应该根据具体的应用场景和性能需求来决定。如果频繁进行随机访问操作,ArrayList是更好的选择;如果频繁进行插入和删除操作,LinkedList可能更合适。

ArrayList 和 Array 和 LinkedList 的区别:

Array 

基本数据结构,可以存储基本类型数据或对象引用。

创建时确定,创建就无法改变

访问元素时,Array 快, Array 直接索引访问。

可以是泛型的

主要是基本的数据访问和修改

ArrayList 

Java集合框架中的一个类,实现了List接口,只能存储对象引用。

是动态的,根据需要自动扩容

ArrayList 在添加或删除元素时可能更高效,尤其是在数组末尾操作时。

 必须是泛型

更多的方法,如添加、删除、迭代等

LinkedList

HashSet是如何保证元素不重复的?(考点:哈希算法、equals和hashCode方法)【简单】

HashSet 是Java集合框架中的一个实现了 Set 接口的类,用于存储不允许重复的元素。HashSet通过以下机制来确保元素的唯一性:

  1. 基于哈希表实现
    • HashSet内部实际上是通过一个 HashMap 来存储元素。每个存储在HashSet中的元素作为HashMap的键(key),对应的值(value)是一个固定的常量对象(通常是一个私有的 PRESENT 对象)。
  2. 使用hashCode()equals()方法
    • hashCode()方法:当向HashSet添加一个元素时,首先调用该元素的 hashCode() 方法来计算其哈希值。这个哈希值决定了元素在哈希表中的存储位置(即桶的位置)。
    • equals()方法:在确定元素存储位置后,HashSet会检查该位置是否已经存在一个具有相同哈希值的元素。如果存在,会调用该元素的 equals() 方法来判断两个元素是否相等。如果两个元素相等,则认为该元素已经存在,添加操作失败;否则,元素被添加到哈希表中。
  3. 避免重复
    • 通过上述的 hashCode() 和 equals() 方法,HashSet可以快速检测和防止重复元素的添加,确保每个元素在Set中是唯一的。

存储不允许重复的元素

基于哈希表实现: HashMap 来存储元素

存储在HashSet中的元素作为键(key),值(value)是一个固定的常量对象

hashCode()方法:添加元素,首先调用 hashCode() 计算其哈希值。哈希值决定了元素在哈希表中的存储位置(即桶的位置)。

equals()方法:在确定元素存储位置后,HashSet会检查该位置是否已经存在一个具有相同哈希值的元素。如果存在,会调用该元素的 equals() 方法来判断两个元素是否相等。如果两个元素相等,则认为该元素已经存在,添加操作失败;否则,元素被添加到哈希表中。

List接口和Set接口的区别是什么?(考点:接口特性、集合类型)【简单】

  • 1、是否允许元素重复
  • 2、是否保证元素的插入顺序
  • 3、元素位置访问:
    • List提供了按照索引访问元素的方法,如:get(),Set没有提供这样的方法

元素重复:list可以

插入顺序:set不保证

位置访问:List提供索引访问的方法

Java中的HashMap了解吗?HashMap 的底层实现是什么?(考点:底层数据结构)【简单】

HashMap存储数据采用了哈希表的结构,底层使用 一维数组+单向链表+红黑树 进行key-value数据的存储

  • 红黑树出现的时机:当某个索引位置i上的链表的长度达到8,且数组的长度超过64时,此索引位置上的元素要从单向链表改为红黑树。--->原因:红黑树进行put()/get()/remove()操作的时间复杂度时o(logn),比单向链表的时间复杂度o(n)好。
  • 红黑树退化成单向链表:如果索引i位置是红黑树的结构,当不断删除元素的情况下,当前索引i位置上的元素的个数低于6时,要从红黑树改为单向链表。

image.png

HashMap存储数据

哈希表结构

底层使用 一维数组+单向链表+红黑树 进行key-value数据的存储

  • 红黑树出现的时机:当某个索引位置i上的链表的长度达到8,且数组的长度超过64时,单向链表改为红黑树。------------>原因:时间复杂度好。
  • 红黑树退化成单向链表:当前索引i位置上的元素的个数低于6时,要从红黑树改为单向链表

HashMap 的扩容机制是怎样的?(考点:数组复制、内存分配)【简单】

简单来说,HashMap 的扩容机制是这样的:

  1. 触发条件: 当 HashMap 中存储的键值对数量(size)超过了一个阈值时,就会触发扩容。这个阈值通常是 当前容量 * 加载因子(loadFactor,默认0.75)

  2. 扩容过程:

    • 创建新数组: 创建一个新的、更大的数组,通常是原数组容量的两倍
    • 重新计算哈希与迁移 (Rehashing): 遍历旧数组中的每一个键值对,重新计算它们在新数组中的位置(因为数组长度变了,哈希映射的索引也会变),然后将它们放入新数组的对应位置。这个过程很重要,因为同一个元素在新旧数组中的桶(bucket)索引很可能不同。
  3. 目的:

    • 减少哈希冲突: 通过扩大数组容量,使得键值对能更均匀地分布,从而减少哈希冲突,保持 HashMap 的查找、插入等操作的效率(接近 O(1))。
    • 保持性能: 如果不扩容,当元素越来越多时,链表(或红黑树)会越来越长,性能会下降。

简单讲就是:装不下了(或快装不下了,为了性能) -> 造个更大的新家 -> 把旧家里的东西重新摆放到新家里。

简单来说,HashMap 的扩容机制是这样的:

  1. 触发条件: 当 HashMap 中存储的键值对数量(size)超过了一个阈值时,就会触发扩容。这个阈值通常是 当前容量 * 加载因子(loadFactor,默认0.75)

  2. 扩容过程:

    • 创建新数组: 创建新的、更大的数组两倍
    • 重新计算哈希与迁移 (Rehashing): 遍历每一个键值对,重新计算位置,放入对应位置
  3. 目的:

    • 减少哈希冲突: 更均匀地分布,从而减少哈希冲突,保持 HashMap 的查找、插入等操作的效率(接近 O(1))。
    • 保持性能: 如果不扩容,当元素越来越多时,链表(或红黑树)会越来越长,性能会下降。

简单讲就是:装不下了(或快装不下了,为了性能) -> 造个更大的新家 -> 把旧家里的东西重新摆放到新家里。

TreeMap和HashMap的区别是什么?(考点:底层数据结构、排序特性)【简单】

  • 实现原理:
    • HashMap基于hash表实现,计算键的hash值来确定存储位置。默认情况下,hashmap不保证元素的存储顺序,从java8之后,h链表过长会转化为红黑树
    • TreeMap基于红黑树实现,是一种自平衡二叉查找树,能够保持键的有序性,因此,TreeMap中的元素总是按照键的自然顺序或者创建时提供的Comparator进行排序。
  • 性能特点:
    • HashMap查找、插入、删除的平均复杂度均为O(1)
    • TreeMap查找、插入、删除的时间复杂度均为O(logn)
  • 实现原理:
    • HashMap基于hash表实现计算键的hash值来确定存储位置不保证元素的存储顺序链表过长会转化为红黑树
    • TreeMap基于红黑树实现,是自平衡二叉查找树保持键的有序性,TreeMap中的元素总是按照键的自然顺序或者创建时提供的Comparator进行排序
  • 性能特点:
    • HashMap平均复杂度均为O(1)
    • TreeMap时间复杂度均为O(logn)

HashSet 和 HashMap 的区别?(考点:底层数据结构)【简单】

  1. 存储内容不同:

    • HashSet:存储的是不重复的单个元素(对象)。它主要用来快速检查某个元素是否存在于集合中。
    • HashMap:存储的是键值对 (Key-Value pairs)。它用来根据键快速查找对应的值。
  2. 内部实现关系:

    • HashSet 内部实际上是基于 HashMap 实现的。当你向 HashSet 添加一个元素时,这个元素会作为 HashMap 的键 (Key),而对应的值 (Value) 则是一个固定的虚拟对象 (dummy Object)。

简单说:

  • HashSet 就像一个只有“物品清单”的集合,只关心物品本身在不在。

  • HashMap 像一个“字典”或“名册”,每个“词条”(键)都有对应的“解释”(值)。

所以,如果你只需要存储一堆不重复的东西,用 HashSet;如果你需要给这些东西关联额外的信息,用 HashMap

  1. 存储内容不同:

    • HashSet不重复的单个元素(对象)。快速检查某个元素是否存在于集合中
    • HashMap键值对 (Key-Value pairs)。根据键快速查找对应的值
  2. 内部实现关系:

    • HashSet 内部实际上是基于 HashMap 实现的。当你向 HashSet 添加一个元素时,这个元素会作为 HashMap 的键 (Key),而对应的值 (Value) 则是一个固定的虚拟对象 (dummy Object)。

简单说:

  • HashSet 就像一个只有“物品清单”的集合,只关心物品本身在不在。

  • HashMap 像一个“字典”或“名册”,每个“词条”(键)都有对应的“解释”(值)。

只需要存储一堆不重复的东西,用 HashSet

需要给这些东西关联额外的信息,用 HashMap

HashMap 和 HashTable 的区别?(考点:底层数据结构)【简单】

简要回答 HashMap 和 Hashtable 的主要区别:

  1. 线程安全性:

    • HashMap非线程安全
    • Hashtable线程安全。它的方法大多是 synchronized 的,并发性能较低。
  2. null 键和 null 值:

    • HashMap允许一个 null 键和多个 null 值。
    • Hashtable不允许 null 键,也不允许 null 值(会抛出 NullPointerException)。
  3. 性能:

    • HashMap:由于非线程安全,单线程下性能通常比 Hashtable 好。
    • Hashtable:由于方法同步,多线程开销较大,性能通常较低。在需要线程安全的场景下,更推荐使用 ConcurrentHashMap
  4. 父类:

    • HashMap:继承自 AbstractMap 类。
    • Hashtable:继承自 Dictionary 类(一个比较老的类)。

总结: Hashtable 是一个遗留的线程安全类,性能较差。如果需要线程安全,推荐使用 ConcurrentHashMap。如果不需要线程安全,使用 HashMap

简要回答 HashMap 和 Hashtable 的主要区别:

  1. 线程安全性:

    • HashMap非线程安全
    • Hashtable线程安全。它的方法大多是 synchronized 的,并发性能较低。
  2. null 键和 null 值:

    • HashMap允许一个 null 键和多个 null 值。
    • Hashtable不允许 null 键,也不允许 null 值(会抛出 NullPointerException)。
  3. 性能:

    • HashMap:由于非线程安全,单线程下性能
    • Hashtable:由于方法同步,多线程开销较大,性能通常较低。在需要线程安全的场景下,更推荐使用 ConcurrentHashMap
  4. 父类:

    • HashMap:继承自 AbstractMap 类。
    • Hashtable:继承自 Dictionary 类(一个比较老的类)。

总结: Hashtable 是一个遗留的线程安全类,性能较差。如果需要线程安全,推荐使用 ConcurrentHashMap。如果不需要线程安全,使用 HashMap

Java的集合类有哪些,那些是线程安全的,那些是线程不安全的?(考点:线程安全)【简单】

Java的集合类

Java的集合主要是由Map和Collection这两个接口派生出来的。Collection接口又派生出三个重要的接口Set, List, Queue。

Java所有的集合类,都是Set, List,Map, Queue这几个接口的实现类。

  • Set接口:Set接口的主要实现类有:HashSet, TreeSet, LinkedHashSet。Set集合最大的特征就是不允许存储重复的元素
  • List接口:List接口的主要实现类有:ArrayList, LinkedList。List接口里面存储的元素是有序的,并且允许存放重复的元素
  • Map接口: Map接口的主要实现类有:HashMap,TreeMap, LinkedHashMap。Map接口存放的就是键值对
  • Queue接口: Queue接口的主要实现类有:ArrayDeque, PriorityQueue。Queue接口主要是用来实现队列的。
线程安全集合类
  • Vector:这个和ArrayList类比较像,只不过Vector中的每个方法都被synchronized关键字修饰,所以Vector集合是线程安全的。
  • HashTable:这个和HashMap类比较像,同样的HashTable中的每个方法都被synchronized关键字修饰。

java.util.concurrent 包提供的都是线程安全的集合:

  • ConcurrentHashMap: ConcurrentHashMap通过锁分离技术实现了线程安全。
线程不安全集合类

ArrayList,LinkedList, HashSet,HashMap,TreeSet,TreeMap 这些类都是线程不安全的集合类,只能在单线程环境下使用,在多线程环境下,如果没有合适的同步措施,就会造成数据不一致等并发问题。

HashMap 为什么是线程不安全的? 如何实现线程安全?(考点:线程安全、底层数据结构)【中等】

  • HashMap是不安全的,主要是因为HashMap内部在多线程并发访问的时候,没有进行同步处理,所以在是线程不安全的
  • 实现HashMap的线程安全有以下几种方法:
    • 调用Collections.syncronizedMap()方法来实现线程安全,会对所有方法调用加锁,确保同一时刻只有一个线程能够访问集合对象
    • 使用线程安全的集合类,如ConcurrentHashMap类,就是线程安全的

Collection接口和Collections类的区别是什么?(考点:接口与类的区别、工具类作用)【简单】

  • collection是一个接口,是java集合框架的根接口之一

  • collections是一个工具类,包含了很多操作集合的静态方法

Vector和ArrayList的区别是什么?(考点:线程安全、性能差异)【简单】

  • 线程安全性:
    • Vector是线程安全的,他的每个方法都被声明为synchronized,多线程环境下可以直接使用不需要额外开销
    • ArrayList不是线程安全
  • 性能:
    • Vector由于所有公开的方法都是同步的,所以性能可能不如ArrayList
  • 扩容机制:
    • Vector容量不足的情况下,会扩容至两倍
    • ArrayList容量不足的情况下,通常会扩容1.5倍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

JBM.下北泽の大天使

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

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

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

打赏作者

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

抵扣说明:

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

余额充值