嘿,Java 爱好者!无论您是试图找出集合存在原因的编码新手,还是身经百战的程序员想知道是否还有更多东西需要学习,本指南都适合您。我们将深入探讨 Java 中 Set 的所有内容,从其核心目的到复杂的工作原理。系好安全带!
首先要做的事情是:什么是 Set,我们为什么要关心?从本质上讲,Set 是一个不能包含重复元素的集合。换句话说,集合中的每个项目都与您的自定义模因集合一样独特。
想象一下,您的任务是为聚会创建宾客名单。您要确保没有人收到两次邀请(因为这很尴尬)。 进入集合。对于 Set,Java 自动确保所有元素都是不同的。它非常适合需要独特性的情况。
不允许重复:Set 最重要的特征是它从不允许重复元素。添加一个已经存在的元素? Java 礼貌地拒绝(不像你的老板有更多的工作)。
无序(通常):集合与列表不同,不关心插入顺序。只要保持独特性,他们就会很高兴。
Null 处理 :某些 Set 允许 null 作为元素,但仅限一次。
现在我们知道了 Set 的作用,让我们看看 Java 提供了哪些类型的 Set:
特性:在 HashMap 的支持下,HashSet 可以快速高效地检查元素是否存在(大多数操作的时间复杂度为 O(1))。
内存布局:在底层使用哈希表,其中基于哈希函数存储元素。
允许空值吗?:可以,但只能有一个。
代码示例 :
Set<String> hashSet = new HashSet<>(); hashSet.add("Apple"); hashSet.add("Banana"); hashSet.add("Apple"); // This will be ignored System.out.println(hashSet); // Output: [Apple, Banana]
特性:HashSet 和 LinkedList 的混合体。
:使用哈希表和双向链表来维护顺序。
:
Set<String> hashSet = new HashSet<>(); hashSet.add("Apple"); hashSet.add("Banana"); hashSet.add("Apple"); // This will be ignored System.out.println(hashSet); // Output: [Apple, Banana]
特点:实现NavigableSet,使用红黑树进行存储。
内存布局:平衡的树结构。
代码示例 :
Set<String> linkedHashSet = new LinkedHashSet<>(); linkedHashSet.add("Apple"); linkedHashSet.add("Banana"); linkedHashSet.add("Orange"); System.out.println(linkedHashSet); // Output: [Apple, Banana, Orange]
让我们掀起引擎盖看看里面。 HashSet 使用 哈希表 进行存储,其中每个元素根据其哈希码分配一个存储桶。添加元素时会发生以下情况:
哈希码计算 :Java 调用 hashCode() 方法获取元素的哈希码。
桶确定 :将哈希码映射到桶(数组索引)。
碰撞处理:如果存储桶已经被占用(碰撞),Java 使用 chaining(较新的 Java 版本中的链表或平衡树)来管理中的多个元素同一个桶。
HashSet结构图:
Set<Integer> treeSet = new TreeSet<>(); treeSet.add(42); treeSet.add(10); treeSet.add(25); System.out.println(treeSet); // Output: [10, 25, 42]
如果您知道正确的技巧,使用集合会很有趣:
[0] -> [Apple] -> [Banana] [1] -> [Grapes] [2] -> [null] [3] -> [Orange] ...
Set<Integer> set1 = new HashSet<>(Arrays.asList(1, 2, 3)); Set<Integer> set2 = new HashSet<>(Arrays.asList(3, 4, 5)); set1.addAll(set2); System.out.println(set1); // Output: [1, 2, 3, 4, 5]
Set<Integer> set1 = new HashSet<>(Arrays.asList(1, 2, 3)); Set<Integer> set2 = new HashSet<>(Arrays.asList(3, 4, 5)); set1.retainAll(set2); System.out.println(set1); // Output: [3]
常见场景:
确保应用程序中唯一的用户名。
在网络爬虫中跟踪 访问过的页面。
维护独特的项目集合(例如,选举中的独特选民)。
需要考虑的危险信号:
如果您需要通过索引访问元素,Set 不是您的朋友。请改用列表。
如果您需要重复项(例如,计算项目的出现次数),请考虑列表或地图。
这是最常用方法的备忘单:
add(E e) :如果元素尚不存在,则添加该元素。
remove(Object o) :删除指定元素(如果存在)。
contains(Object o) :检查某个元素是否在 Set 中。
size() :返回元素的数量。
clear() :删除所有元素。
isEmpty() :检查 Set 是否为空。
iterator() :返回元素上的迭代器。
Set<String> hashSet = new HashSet<>(); hashSet.add("Apple"); hashSet.add("Banana"); hashSet.add("Apple"); // This will be ignored System.out.println(hashSet); // Output: [Apple, Banana]
并发集 :
使用 ConcurrentHashMap.newKeySet() 或 CopyOnWriteArraySet 进行线程安全操作。
不可变集 :
使用 Collections.unmodifyingSet() 或 Set.of() 创建只读集。
Set<String> linkedHashSet = new LinkedHashSet<>(); linkedHashSet.add("Apple"); linkedHashSet.add("Banana"); linkedHashSet.add("Orange"); System.out.println(linkedHashSet); // Output: [Apple, Banana, Orange]
HashSet 是大多数任务的最佳选择,因为它在添加、删除和检查元素方面具有 O(1) 性能。 TreeSet 具有较高的成本 (O(log n)),但增加了自然排序的好处。 LinkedHashSet 给出了可预测的迭代顺序,并且开销很小。
认识问题类型 :
唯一性检查(例如,查找文档中的唯一单词)。
设置操作(例如,查找用户之间的共同好友)。
快速查找,不重复(例如,在恒定时间内检查元素是否存在)。
虽然集合可能不像列表那样迷人,也不像地图那样神秘,但它们在有效维护唯一集合方面发挥着至关重要的作用。他们是无名英雄,可确保您的数据保持干净和独特,使您免于那些可能导致意外结果的讨厌的重复。无论您是在优化算法、确保数据完整性,还是只是尝试选择一个的结构只是有效,从内到外理解集合将使您成为更强大的开发人员。因此,充满信心地继续编码,知道您已经释放了强大集合的真正潜力!
这是一个包装,伙计们!
以上是Java 集合的终极指南:揭开这个不起眼的数据结构的每一个秘密的详细内容。更多信息请关注PHP中文网其他相关文章!