Java集合框架学习应先厘清Collection与Map的分工边界:ArrayList仅实现List接口,不支持队列操作;LinkedList实现Deque接口,支持双端操作;HashSet依赖hashCode()与equals()协同;遍历时删除需用迭代器或removeIf();接口设计反映抽象本质。

学Java集合框架,别从源码或思维导图开始——先搞懂Collection和Map这两大根接口的分工与边界,否则后面所有“原理”都容易理解错。
为什么ArrayList不能直接当队列用,但LinkedList可以?
因为接口契约不同:ArrayList只实现了List接口,而LinkedList额外实现了Deque接口(双端队列)。这意味着你调用addFirst()、removeLast()这些方法时,ArrayList根本不存在对应方法,编译就报错。
- 想模拟栈/队列行为,优先选
LinkedList或更明确的ArrayDeque(性能更好,且不支持null) - 别用
ArrayList.add(0, x)模拟入队——每次都在头部插入,时间复杂度是O(n),链表类才是O(1) -
LinkedList.get(i)在大数据量下很慢,它不是“也能随机访问”,而是“被迫遍历”,别被IDE自动补全骗了
HashSet里存自定义对象,为什么contains()总返回false?
因为HashSet依赖hashCode()和equals()协同工作:先算哈希值定位桶,再用equals()比对具体内容。如果只重写equals()不重写hashCode(),两个逻辑上相等的对象可能落在不同桶里,永远搜不到。
- 只要重写了
equals(),就必须同步重写hashCode(),这是硬约束 - IDE生成的
hashCode()默认基于所有字段,但如果某个字段参与了equals()判断却没进hashCode()计算,依然会出错 -
String、Integer等JDK内置类型已正确实现,可放心用;自定义类务必检查这两方法是否成对覆盖
遍历List时删元素,为什么for(int i=0; i会漏删或越界?
因为remove(i)执行后,后续元素集体前移,但循环变量i仍自增,导致跳过下一个元素;若删到最后还继续get(i),就会抛IndexOutOfBoundsException。
- 安全做法是倒序删:
for(int i = list.size()-1; i >= 0; i--),或用迭代器Iterator.remove() -
list.remove("xxx")是按值删除,会遍历找第一个匹配项;list.remove(0)是按索引删除,两者签名不同,别混淆 - 批量删除建议用
removeIf(),语义清晰且由集合自己控制迭代过程,避免手动索引错误
集合框架最易卡壳的地方,从来不是“怎么写”,而是“为什么这个接口不提供那个方法”——比如Collection没有get(int),是因为它不承诺有序;Map不继承Collection,是因为键值对模型和单元素模型本质不同。盯着接口定义看两分钟,比查十篇博客更管用。









