【Java 集合】

Java集合常见面试题总结(上)

集合概述

Java 集合概览

Java 集合,也叫作容器,主要是由两大接口派生而来:一个是 Collection接口,主要用于存放单一元素;另一个是 Map 接口,主要用于存放键值对。对于Collection 接口,下面又有三个主要的子接口:ListSet 、 Queue

Java 集合框架如下图所示:

Java 集合框架概览

Java 集合框架概览

注:图中只列举了主要的继承派生关系,并没有列举所有关系。比方省略了AbstractListNavigableSet等抽象类以及其他的一些辅助类,如想深入了解,可自行查看源码。

如何选用集合?

  • 我们只需要存放 单个元素值时,就选择实现 Collection 接口的集合。需要保证 元素 唯一就选择实现 Set 接口的下面集合比如  HashSet,如果 要保证有序,就选择实现 List 接口的比如 ArrayList。
  • 我们需要 存放键值对,就选用 Map 接口下的集合。如果需要 有序 就选择 TreeMap,需要   保证  线程安全  就选用 ConcurrentHashMap,其他情况的话 就选择 HashMap。

使用集合的好处?

当我们需要存储一组类型相同的数据时,数组是最常用且最基本的容器之一。但是,使用数组存储对象存在一些不足之处,因为在实际开发中,存储的数据类型多种多样且数量不确定。这时,Java 集合就派上用场了。与数组相比,Java 集合提供了更灵活、更有效的方法来存储多个数据对象。Java 集合框架中的各种集合类和接口可以存储不同类型和数量的对象,同时还具有多样化的操作方式。相较于数组,Java 集合的优势在于它们的大小可变、支持泛型、具有内建算法等。总的来说,Java 集合提高了数据的存储和处理灵活性,可以更好地适应现代软件开发中多样化的数据需求,并支持高质量的代码编写。

List

ArrayList 和  (数组)的区别?

  • 数组 被创建之后,长度固定,不能改变;ArrayList 可以动态地扩容 长度。
  • 数组 不支持泛型,ArrayList 可以使用 泛型<T> ,来确保类型安全。
  • 数组 只能通过  下标 访问元素,不提供 api 方法;ArrayList  提供了丰富的 API 方法,比如 add()remove() 增删元素的方法

下面是二者使用的简单对比:

Array

 // 初始化一个 String 类型的数组
 String[] stringArr = new String[]{"hello", "world", "!"};
 // 修改数组元素的值
 stringArr[0] = "goodbye";
 System.out.println(Arrays.toString(stringArr));// [goodbye, world, !]
 // 删除数组中的元素,需要手动移动后面的元素
 for (int i = 0; i < stringArr.length - 1; i++) {
     stringArr[i] = stringArr[i + 1];
 }
 stringArr[stringArr.length - 1] = null;
 System.out.println(Arrays.toString(stringArr));// [world, !, null]

ArrayList :

// 初始化一个 String 类型的 ArrayList
 ArrayList<String> stringList = new ArrayList<>(Arrays.asList("hello", "world", "!"));
// 添加元素到 ArrayList 中
 stringList.add("goodbye");
 System.out.println(stringList);// [hello, world, !, goodbye]
 // 修改 ArrayList 中的元素
 stringList.set(0, "hi");
 System.out.println(stringList);// [hi, world, !, goodbye]
 // 删除 ArrayList 中的元素
 stringList.remove(0);
 System.out.println(stringList); // [world, !, goodbye]

ArrayList 和 Vector 的区别?(了解即可)

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

Vector 和 Stack 的区别?(了解即可)

  • Vector 和 Stack 两者都是线程安全的,都是使用 synchronized 关键字进行同步处理。
  • Stack 继承自 Vector,是一个后进先出的栈,而 Vector 是一个列表。

随着 Java 并发编程的发展,Vector 和 Stack 已经被淘汰,推荐使用并发集合类(例如 ConcurrentHashMapCopyOnWriteArrayList 等)或者手动实现线程安全的方法来提供安全的多线程操作支持。

 ArrayList 与 LinkedList 区别?

  • 是否保证线程安全: ArrayList 和 LinkedList 都是线程不安全的
  • 底层数据结构: ArrayList 底层使用的是 Object 数组,查询速度快,增删改 慢;LinkedList 底层使用的是 双向链表,查询速度慢 ,增删改 快。
  • 插入元素的时间复杂度:
    • ArrayList ,头部插入,由于需要将所有元素都依次向后移动一个位置,因此时间复杂度是 O(n);尾部插入,当 ArrayList 的容量未达到阈值时,只需要在数组末尾添加一个元素即可,时间复杂度是 O(1)。当容量已达到阈值时,就需要扩容,将原数组复制到新的更大的数组中,时间复杂度O(n);指定位置插入,需要将目标位置之后的所有元素都向后移动一个位置,然后再把新元素放入指定位置,因此时间复杂度为 O(n)。
    • LinkedList 在 头尾 插入元素时,只需要修改头尾结点的指针就行,所以时间复杂度为 O(1);但是如果要在指定位置 i  插入元素时候,需要先遍历到指定位置i,再修改指定节点的指针,所以时间复杂度为 O(n)。

说一说 ArrayList 的扩容机制吧​​​​​​​

具体具体看这篇文章,ArrayList 扩容机制​​​​​​​

ArrayList 可以添加 null 值吗?

ArrayList 中可以存储任何类型的对象,包括 null 值。不过,不建议向ArrayList 中添加 null 值, null 值无意义,会让代码难以维护比如忘记做判空处理就会导致空指针异常。

示例代码:

ArrayList<String> listOfStrings = new ArrayList<>();
listOfStrings.add(null);
listOfStrings.add("java");
System.out.println(listOfStrings);

输出:

[null, java]

LinkedList 为什么不能实现 RandomAccess 接口?

由于 LinkedList 底层数据结构是 链表,内存地址 不连续,不支持随机快速访问,所以不能实现 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值