contains 查的是元素的逻辑相等,即调用 equals() 方法而非 ==;自定义类必须重写 equals() 和 hashCode(),否则可能始终返回 false;ArrayList.contains 是 O(n) 顺序查找,HashSet.contains 平均 O(1) 哈希查找。

contains 方法到底查的是什么
contains 判断的是元素的「逻辑相等」,不是引用相等。它内部调用的是 equals() 方法,不是 ==。所以如果你往 ArrayList 或 HashSet 里存自定义对象,却没重写 equals()(以及配套的 hashCode()),contains 很可能永远返回 false,哪怕对象字段一模一样。
- 对
String、Integer等 JDK 类型,没问题——它们已重写equals - 对自定义类,必须同时重写
equals(Object obj)和hashCode(),否则在HashSet/HashMap中会失效 - 注意:
Arrays.asList(...).contains(...)本质是ArrayList的contains,仍走equals流程
ArrayList.contains 和 HashSet.contains 性能差多少
表面上都是 contains,但底层行为完全不同:
-
ArrayList.contains是顺序遍历,时间复杂度 O(n),遇到第一个匹配就停 -
HashSet.contains是哈希寻址,平均 O(1),但前提是hashCode()分布合理;若大量哈希冲突,退化为链表/红黑树查找,最坏 O(log n) 或 O(n) - 如果集合长期只读、元素不多(比如 ArrayList 可能更快(无哈希计算开销 + cache 友好)
- 如果频繁调用
contains且集合较大,优先选HashSet,但记得检查hashCode实现是否合理
contains 在 null 元素上怎么表现
不同集合处理 null 的策略不一致,容易踩坑:
-
ArrayList、LinkedList、ArrayDeque允许存null,contains(null)返回true当且仅当集合中存在某个元素e == null(即用==判空,不是equals) -
HashSet、LinkedHashSet也允许null,contains(null)同样用==判,能正确识别 -
TreeSet默认不允许null,调用contains(null)会抛NullPointerException(除非构造时传了支持null的Comparator)
Setset = new TreeSet<>(); // 默认自然排序 set.contains(null); // 抛 NullPointerException
Stream.filter + findAny 代替 contains?
有人想用 stream().anyMatch(...) 替代 contains,尤其想加条件判断时。但要注意:
立即学习“Java免费学习笔记(深入)”;
- 对
List,list.contains(x)是直接查值;而list.stream().anyMatch(e -> e.equals(x))效果相同,但多了 stream 创建和 lambda 调用开销 - 如果要查「满足某条件的对象」(比如
user.getName().equals("Alice")),那contains无能为力,必须用anyMatch或手动遍历 - 别为了“函数式风格”强行替换——
contains语义清晰、性能明确;anyMatch适合复杂谓词,不是它的替代品
真正容易被忽略的是:集合类型决定了你该用哪个工具。查固定值优先 contains;查动态条件才轮到 anyMatch 或 stream().filter(...).findFirst()。










