

ArrayList 的动态扩容是 Java 面试的必考点,重点在于“为什么”和“怎么做”。
new ArrayList() 时,系统并不会立刻分配 10 个空间,而是先给一个空数组。只有在第一次执行 add 操作时,才会真正分配 10 个单位的内存。
int newCapacity = oldCapacity + (oldCapacity >> 1)。
>> 1 相当于除以 2,这在 CPU 层面执行极快,减少了运算时间。
Arrays.copyOf 复制老数据、更新引用。在大数据量下,建议初始化时指定 initialCapacity 以减少扩容次数。
这种 List 的设计初衷是为了解决多线程遍历时不抛出 ConcurrentModificationException。
add)必须加锁(JDK 8 用 ReentrantLock,JDK 11+ 用 synchronized),确保同一时刻只有一个线程在写。
setArray(newElements) 改变 volatile 指针的指向。
volatile 修饰,保证了一旦写线程完成引用替换,读线程能立刻感知到新地址。
get)完全不加锁,性能极高。
Stream 让集合处理变得像流水线一样高效。
filter(p):保留符合条件的元素。
map(f):转换元素类型(如将 User 对象转为 String 姓名)。
sorted():排序。
distinct():去重。
collect(Collectors.toList()):将结果收集回 List。
forEach(c):逐个处理。
count():统计个数。
anyMatch(p):只要有一个符合条件就返回 true(短路操作)。
这是判断候选人对数据结构理解深度的重要题目。
put 时,由于没有加锁,后一个线程的写入仍可能覆盖前一个线程的写入。
ConcurrentHashMap。它在 JDK 1.8 中通过 volatile + CAS + synchronized 的组合拳,将锁的粒度细化到了每个哈希桶的头节点上。
学习感悟:
今天的复习让我明白,Java 集合的设计核心就在于“在性能、安全和功能之间做取舍”。没有最好的结构,只有最适合场景的工具。