2.Java面试题——集合

1.Java中集合是什么?

Java中的集合是Java编程语言提供的一种数据结构,用于存储、操作和处理一组数据。它是Java编程语言中非常重要的一部分,广泛应用于各种Java应用程序的开发中。Java集合框架提供了一系列类和接口,用于实现不同类型的集合。

2.集合的关系是什么?

集合关系

3.每种集合实现的优缺点是什么?

  • Collection接口:
    • List接口:有序, 可重复
      • ArrayList
        • 优点: 底层数据结构是数组,查询快,增删慢。
        • 缺点: 线程不安全,效率高
      • LinkedList
        • 优点: 底层数据结构是链表,查询慢,增删快。
        • 缺点: 线程不安全,效率高
      • Vector
        • 优点: 底层数据结构是数组,查询快,增删慢。
        • 缺点: 线程安全,效率低, 已给舍弃了
    • Set接口:无序,唯一
      • HashSet:无序,唯一
        • 底层数据结构是哈希表。
        • 如何来保证元素唯一性? 依赖两个方法:hashCode()和 equals()
      • LinkedHashSet:FIFO 插入有序,唯一
        • 底层数据结构是链表和哈希表。
        • 由链表保证元素有序
        • 由哈希表保证元素唯一
      • TreeSet:唯一,有序
        • 底层数据结构是红黑树。
        • 如何保证元素排序的呢?自然排序比较器排序
        • 如何保证元素唯一性的呢?根据比较的返回值是否是 0 来决定
  • Map接口:
    • HashMap
      • 基于 hash 表的 Map 接口实现,非线程安全,高效,支持 null 值和null 键,线程不安全。
    • HashTable
      • 线程安全,低效,不支持 null 值和 null 键;
    • LinkedHashMap
      • 线程不安全,是 HashMap 的一个子类,保存了记录的插入顺序;
    • TreeMap
      • 能够把它保存的记录根据键排序,默认是键值的升序排序,线程不安全。

扩展:问到List 和 Map、Set 的实现类有哪些也可以按照上面的回答,但不需要回答优缺点,问什么就会回答什么。

4.集合和数组的区别?

区别:数组长度固定 集合长度可变
数组中存储的是同一种数据类型的元素,可以存储基本数据类型,也可以存储引用数据类型;
集合存储的都是对象,而且对象的数据类型可以不一致。在开发当中一般当对象较多的时候,使用集合来存储对象。

5.List 和 Map、Set 的区别

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

6.ArrayList和LinkedList有什么区别?

ArrayList 和 LinkedList 是 Java 集合框架(Java Collections
Framework)中两种常用的列表(List)实现,它们之间存在一些关键的区别,主要体现在它们的内部实现、性能特点、以及适用场景上。

  • 内部实现
    • ArrayList:基于动态数组实现。当元素被添加到 ArrayList
      中时,如果数组的大小不足以容纳所有元素,则会自动扩容(通常是当前容量的1.5倍)。这意味着 ArrayList在随机访问(即通过索引访问)时非常快,但在列表的开头或中间插入、删除元素时可能会比较慢,因为可能需要移动大量的元素。
    • LinkedList:基于双向链表实现。每个元素都包含了指向前一个元素和后一个元素的引用。因此,LinkedList在插入、删除元素时(特别是在列表的开头或中间)通常比ArrayList 快,因为不需要移动其他元素。然而,由于需要遍历链表来访问特定位置的元素,所以 LinkedList在随机访问时相对较慢。
  • 性能特点
    • 随机访问:ArrayList 优于 LinkedList。
    • 插入和删除操作:在列表的开头或中间位置时,LinkedList 通常优于
      ArrayList;但在列表的末尾添加元素时,两者的性能差异不大。
    • 内存消耗:LinkedList 的每个节点除了存储数据外,还需要存储两个引用(指向前一个和后一个节点的引用),因此其内存消耗通常比ArrayList 更高。
  • 适用场景
    • 如果你需要频繁地在列表的任意位置进行插入和删除操作,并且不关心随机访问的性能,那么 LinkedList 可能是更好的选择。
    • 如果你需要频繁地通过索引来访问元素,且插入和删除操作主要在列表的末尾进行,那么 ArrayList 将是更高效的选择。
  • 线程安全性
    • 两者都不是线程安全的。如果你需要在多线程环境中使用它们,那么你需要自己实现同步控制,或者使用Vector、Collections.synchronizedList() 方法来包装它们,或者使用 Java 并发包中的并发集合类(如ConcurrentHashMap 的分割器)。

7.说一下ArrayList的扩容机制?

  • 初始容量
    • 当创建ArrayList时,可以指定一个初始容量(initialcapacity)。如果没有指定,则默认容量为10(这个值在ArrayList的源码中定义为DEFAULT_CAPACITY)。
  • 扩容触发条件
    • 当向ArrayList中添加元素,且当前容量不足以容纳新元素时,就会触发扩容操作。具体来说,当调用add()方法时,ArrayList会先检查当前容量是否足够,如果不够,则进行扩容。
  • 扩容过程
    • 计算新容量:ArrayList的扩容操作通过调用grow()方法实现,该方法会计算出一个新的容量值。在Java8及之后的版本中,默认情况下,新容量是旧容量的1.5倍(即newCapacity = oldCapacity + (oldCapacity>> 1))。这意味着每次扩容后,ArrayList的容量都会以1.5倍的速度增长。
    • 创建新数组:根据计算出的新容量,ArrayList会创建一个新的数组,用于存储扩容后的元素。
    • 复制元素:将原数组中的所有元素复制到新数组中。这一步是扩容操作中最耗时的部分,因为它需要遍历原数组并将每个元素复制到新数组的相应位置。
    • 更新引用:将ArrayList的内部数组引用更新为新创建的数组,以便后续操作都在新数组上进行。
  • 扩容操作的性能影响
    • 由于扩容操作涉及创建新数组和复制元素,因此它具有一定的性能开销。如果频繁地向ArrayList中添加大量元素,扩容操作可能会成为性能瓶颈。
    • 为了减少扩容操作的频率,可以在创建ArrayList时指定一个较大的初始容量,或者在添加大量元素之前使用ensureCapacity()方法显式地增加容量。
  • 扩容策略的历史变化
    • 值得注意的是,在Java 7及之前的版本中,ArrayList的扩容策略是容量翻倍(即新容量是旧容量的两倍)。但从Java8开始,为了优化内存使用,扩容策略改为了容量增长1.5倍。
  • 总结
    • ArrayList通过动态扩容机制,实现了其容量的自动增长,从而能够灵活地存储更多的元素。然而,扩容操作会带来一定的性能开销,因此在设计程序时应合理预估所需容量,以减少扩容次数,提高性能。

未完结,待续…

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Retrograde-lx

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

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

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

打赏作者

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

抵扣说明:

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

余额充值