1.2 快速复习——ArrayList 原理&面试题汇总

269 阅读3分钟

Java ArrayList 原理及面试题总结

简介

ArrayList 是 Java 集合框架中最常用的动态数组实现,提供了快速随机访问的能力。它是 List 接口的非同步实现,允许包含重复元素,并且可以包含 null 值。本文将简要介绍 ArrayList 的工作原理,并总结一些常见的面试题。

原理

ArrayList 在内部使用一个可动态扩展的数组(Object[] 类型)来存储元素。当添加元素到 ArrayList 时,如果当前数组容量不足以添加新元素,会自动进行扩容。扩容过程中,ArrayList 会创建一个新的数组,其容量为原数组容量的 1.5 倍,并复制原数组中的元素到新数组中。

扩容机制

  • 当 ArrayList 的大小超过其容量时,需要进行扩容。
  • 默认初始容量为 10,加载因子(扩容因子)为 0.5,即当 ArrayList 的大小达到 15 时进行扩容。
  • 扩容时,创建一个新数组,其长度为原数组长度的 1.5 倍,并将原数组元素复制到新数组中。

扩容复制使用System.arraycopy方法,这是定义在 java.lang.System 类中的一个静态 native 方法,在其底层实现中,会根据传入的参数计算源数组和目标数组的内存地址,然后执行内存块的复制操作。这个操作通常是通过调用操作系统提供的内存复制函数来完成的,例如在 Linux 系统中可能会使用 memcpy 函数。

面试题总结

1. ArrayList 能否包含 null 值?

可以。ArrayList 允许存储 null 值,但只允许存储一个 null 元素。

2. ArrayList 与 LinkedList 的区别是什么?

  • 访问性能:ArrayList 提供快速的随机访问能力,而 LinkedList 在随机访问时性能较差。
  • 内存消耗:ArrayList 占用的内存较少,LinkedList 需要额外存储节点引用。
  • 插入和删除:ArrayList 在非尾部插入或删除元素时需要移动后续元素,而 LinkedList 可以在任意位置高效地进行插入和删除操作。

3. ArrayList 的初始容量和负载因子是什么意思?

ArrayList 有初始容量的概念,这是指创建 ArrayList 时数组的大小。但需要注意的是,ArrayList 没有负载因子的概念,这是 HashMap 的一个特性。负载因子用于决定 HashMap 的扩容时机。

4. ArrayList 的扩容机制是怎样的?

当 ArrayList 的元素数量超过其当前容量时,会自动扩容。扩容时,会创建一个新的数组,其长度为原数组长度的 1.5 倍,并将原数组中的元素复制到新数组中。

5. ArrayList 为什么不是线程安全的?

ArrayList 并不是为线程安全设计的。它的所有操作都不是同步的,这意味着在多线程环境下,如果多个线程同时修改 ArrayList,可能会导致不可预测的结果。

6. 如何实现一个不可修改的 ArrayList?

可以使用 Collections.unmodifiableList 方法来创建一个不可修改的 ArrayList。任何试图修改这个 ArrayList 的操作都会抛出 UnsupportedOperationException 异常。

7. ArrayList 的 get(int index) 方法时间复杂度是多少?

ArrayList 的 get(int index) 方法时间复杂度为 O(1),因为它直接通过索引访问数组元素。

8. ArrayList 的 add(E e) 方法在什么情况下会抛出异常?

ArrayList 的 add(E e) 方法通常不会抛出异常,除非 e 是 null 并且 ArrayList 禁止存储 null 值,或者 e 的类型与 ArrayList 存储的元素类型不兼容。

参考链接

ArrayList 原理&面试题汇总