Collection和Map是Java集合框架两个独立顶层接口,互不继承;Collection下分List、Set、Queue三条主线,Map则自成体系,二者抽象维度不同故无法统一为单接口。

Collection 和 Map 是 Java 集合框架的两个独立顶层接口
Java 集合框架没有单一“顶级接口”,而是并列存在两个根接口:Collection 和 Map。它们互不继承,也不共享父接口(Collection 继承自 Iterable,但 Map 没有),这是初学者最容易混淆的起点。
常见错误现象:试图把 HashMap 当作 Collection 的子类来用,结果发现不能直接传给接受 Collection<?> 参数的方法;或者误以为 Map 里存的是“键值对对象”,其实它存的是两组独立视图(keySet()、values()、entrySet())。
-
Collection下分三条主线:List(有序可重复)、Set(无序不重复)、Queue(队列行为,含Deque) -
Map不属于Collection体系,它自己就是顶层,实现类如HashMap、TreeMap、LinkedHashMap - 注意
Collection接口方法如add()、remove()操作单个元素;而Map的put()、get()必须同时处理 key 和 value
为什么没有 Collection<K, V> 这样的泛型统一接口
因为 Collection 抽象的是“一组同类型元素”,而 Map 管理的是“键与值之间的映射关系”——这是两种不同抽象维度,强行合并会导致语义失真和 API 膨胀。
例如,如果让 Map 实现 Collection,那 add(new Pair<String,Integer>("a",1)) 是加键?加值?还是加整个映射?JDK 设计者选择保持分离,用 entrySet() 显式暴露映射单元(Map.Entry)来桥接。
立即学习“Java免费学习笔记(深入)”;
-
Map.Entry是唯一能同时访问 key 和 value 的标准载体,但它只是视图接口,不可直接实例化 -
Collection的泛型是单参数(<E>),Map是双参数(<K,V>),JVM 泛型擦除后底层签名完全不同,无法统一 - 性能上,
Map的查找基于 hash 或比较,Collection的遍历/查找依赖具体实现(如ArrayList的 O(1) get vsLinkedList的 O(n))
实际编码中容易踩的坑:null 值、线程安全、fail-fast
这三个问题不是理论细节,而是上线后高频报错来源。
-
HashMap允许一个nullkey 和任意个nullvalue;TreeMap不允许nullkey(会抛NullPointerException),value 倒是随意;ConcurrentHashMap则完全禁止nullkey 和nullvalue -
ArrayList、HashMap都是非线程安全的,多线程写入不加同步会触发ConcurrentModificationException—— 注意这个异常不一定在写时抛,而常在后续迭代时爆发 -
Iterator的remove()是安全的,但用for-each循环里调list.remove()就会 fail-fast;正确做法是用Iterator.remove()或收集待删索引再倒序删
别被“体系图解”带偏:重点看接口契约,不是继承树
画得再漂亮的 UML 图,也掩盖不了一个事实:真正决定行为的是接口定义的方法契约,而不是类图连线。比如 HashSet 和 TreeSet 都实现 Set,但前者用哈希表、后者用红黑树,add() 时间复杂度分别是 O(1) 平均和 O(log n),可它们都必须保证“不重复”这一契约。
- 看文档时盯紧
Collection.add()的返回值含义:成功添加返回true,已存在则返回false(Set)或总是true(List) -
Map.put()返回的是“被替换的旧值”,首次插入返回null—— 但若原 value 就是null,你就无法区分,此时该用computeIfAbsent()等更明确的方法 - JDK 8+ 后大量默认方法(如
Collection.removeIf()、Map.compute())改变了使用习惯,别只盯着老式 for 循环
真正难的不是记住谁继承谁,而是理解每个接口方法在不同实现下的副作用、并发表现和边界行为。图可以帮你入门,但线上问题从来不在图里。










