HashSet

HashSet 类注释

这个类实现了Set接口,由一个哈希表(实际上是一个HashMap实例)支持。它不保证集合的迭代顺序;特别是,它不能保证订单在一段时间内保持不变。此类允许使用null元素。

这个类为基本操作(添加、删除、包含和大小)提供了恒定的时间性能,假设哈希函数将元素正确地分散在存储桶中。

在此集合上迭代需要与HashSet实例的大小(元素数量)加上支持HashMap实例的“容量”(存储桶数量)之和成比例的时间。

因此,如果迭代性能很重要,那么不要将初始容量设置得太高(或负载系数设置得太低),这一点非常重要。

请注意,此实现不是同步的。如果多个线程同时访问一个哈希集,并且至少有一个线程修改了该集,则必须对其进行外部同步。这通常是通过对一些自然封装集合的对象进行同步来实现的。如果不存在这样的对象,则应使用Collections“包装”集合。synchronizedSet方法。最好在创建时执行此操作,以防止意外地对集合进行不同步的访问:

设置s=集合。synchronizedSet(new HashSet(…));

此类迭代器方法返回的迭代器是快速失效的:如果在迭代器创建后的任何时候,以除迭代器自己的remove方法之外的任何方式修改集合,则迭代器将抛出ConcurrentModificationException。因此,面对并发修改,迭代器会迅速而干净地失败,而不是冒着在未来不确定的时间出现任意、不确定行为的风险。

请注意,迭代器的快速失效行为是无法保证的,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬保证。故障快速迭代器在尽力而为的基础上抛出ConcurrentModificationException。因此,编写依赖于此异常的正确性的程序是错误的:迭代器的快速故障行为应该只用于检测错误。

此类是Java Collections Framework的成员。

1、HashSet 定义

        HashSet 是一个由 HashMap 实现的集合。元素无序且不能重复。

相对于早期版本的 JDK HashMap 实现,新增了红黑树作为底层数据结构,在数据量较大且哈希碰撞较多时,能够极大的增加检索的效率。

HashMap 作为底层数据结构实现的一种数据结构——HashSet

public class HashSet extends AbstractSet implements Set, Cloneable, java.io.Serializable {

........

}

和前面介绍的大多数集合一样,HashSet 也实现了 Cloneable 接口和 Serializable 接口,分别用来支持克隆以及支持序列化。还实现了 Set 接口,该接口定义了 Set 集合类型的一套规范。

2、字段属性

//HashSet集合中的内容是通过 HashMap 数据结构来存储的

private transient HashMap map;

//向HashSet中添加数据,数据在上面的 map 结构是作为 key 存在的,而value统一都是 PRESENT persent

private static final Object PRESENT = new Object();

第一个定义一个 HashMap,作为实现 HashSet 的数据结构

第二个 PRESENT 对象,因为前面讲过 HashMap 是作为键值对 key-value 进行存储的,而 HashSet 不是键值对,

那么选择 HashMap 作为实现,其原理就是存储在 HashSet 中的数据 作为 Map 的 key,而 Map 的value

统一为 PRESENT(下面介绍具体实现时会了解)。

3、构造函数

无参构造

public HashSet() {

        map = new HashMap<>();

}

直接 new 一个 HashMap 对象出来,采用无参的 HashMap 构造函数,具有默认初始容量(16)和加载因子(0.75)。

指定初始容量

public HashSet(int initialCapacity) {

        map = new HashMap<>(initialCapacity);

}

指定初始容量和加载因子

public HashSet(int initialCapacity, float loadFactor) {

        map = new HashMap<>(initialCapacity, loadFactor);

}

构造包含指定集合中的元素

public HashSet(Collection c) {

        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));

        addAll(c);

}

4、添加元素

public boolean add(E e) {

        return map.put(e, PRESENT)==null;

}

通过 map.put() 方法来添加元素,说明了该方法如果新插入的key不存在,则返回null,如果新插入的key存在,则返回原key对应的value值(注意新插入的value会覆盖原value值)。

也就是说 HashSet 的 add(E e) 方法,会将 e 作为 key,PRESENT 作为 value 插入到 map 集合中,

如果 e 不存在,则插入成功返回 true;如果存在,则返回false。

5、删除元素

public boolean remove(Object o) {

        return map.remove(o)==PRESENT;

}

调用 HashMap 的remove(Object o) 方法,该方法会首先查找 map 集合中是否存在 o ,如果存在则删除,并返回该值,

如果不存在则返回 null。也就是说 HashSet 的 remove(Object o) 方法,删除成功返回 true,删除的元素不存在会返回 false。

6、查找元素

public boolean contains(Object o) {

        return map.containsKey(o);

}

调用 HashMap 的 containsKey(Object o) 方法,找到了返回 true,找不到返回 false。

7、遍历元素

HashSet set = new HashSet<>();

        set.add(1);

        set.add(2);

        //增强for循环

        for( Integer i : set ) {

                System.out.println(i);

        }

        //普通for循环

        Iterator iterator = set.iterator();

        while (iterator.hasNext()){

        System.out.println(iterator.next());

        }

09-24
### HashSet 介绍 HashSetJava 集合框架中的一个类,它实现了 Set 接口,基于哈希表(实际上是一个 HashMap 实例)来存储元素。HashSet 不允许存储重复的元素,并且不保证元素的顺序,因为它不维护元素的插入顺序或其他特定顺序。哈希技术是 Java 集合框架的基石,深入理解 HashSet 的实现原理,能提升代码性能,培养底层思维[^1]。 ### 使用方法 #### 1. 创建 HashSet ```java import java.util.HashSet; public class HashSetExample { public static void main(String[] args) { // 创建一个 HashSet 对象 HashSet<String> set = new HashSet<>(); // 使用 with_hasher 方法创建具有指定哈希函数的 HashSet(这里只是示例语法,实际 Java 里不是这种写法) // 假设存在自定义哈希函数 MyHasher // HashSet<String, MyHasher> setWithHasher = HashSet.with_hasher(new MyHasher()); } } ``` #### 2. 添加元素 ```java import java.util.HashSet; public class HashSetExample { public static void main(String[] args) { HashSet<String> set = new HashSet<>(); // 添加元素 boolean result1 = set.add("apple"); boolean result2 = set.add("banana"); boolean result3 = set.add("apple"); // 重复元素,添加失败 System.out.println(result1); // 输出: true System.out.println(result2); // 输出: true System.out.println(result3); // 输出: false } } ``` 这里的 `add` 方法有返回值,如果传入的元素是集合中不存在的新值,返回 `true` 表示添加成功;如果传入的是集合中已存在的重复值,返回 `false` 表示添加失败,其内部实现是适配到 `HashMap` 上完成的,`HashSet` 的 `add` 方法通过 `HashMap.put` 方法的返回结果来判断是否添加成功[^3][^5]。 #### 3. 判断元素是否存在 ```java import java.util.HashSet; public class HashSetExample { public static void main(String[] args) { HashSet<String> set = new HashSet<>(); set.add("apple"); boolean contains = set.contains("apple"); System.out.println(contains); // 输出: true } } ``` #### 4. 删除元素 ```java import java.util.HashSet; public class HashSetExample { public static void main(String[] args) { HashSet<String> set = new HashSet<>(); set.add("apple"); boolean removed = set.remove("apple"); System.out.println(removed); // 输出: true } } ``` #### 5. 遍历元素 ```java import java.util.HashSet; import java.util.Iterator; public class HashSetExample { public static void main(String[] args) { HashSet<String> set = new HashSet<>(); set.add("apple"); set.add("banana"); // 使用迭代器遍历 Iterator<String> iterator = set.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } // 使用增强 for 循环遍历 for (String element : set) { System.out.println(element); } } } ``` ### 相关技术细节 - **哈希函数**:`HashSet` 依赖于元素的 `hashCode` 方法来确定元素在哈希表中的存储位置。`Object` 类的 `hashCode` 方法返回的哈希码具有地址唯一性,但为了让程序的运行逻辑符合现实生活(即属性相同的对象被看作同一个对象),`Object` 的子类通常会重写 `hashCode` 方法,基本数据类型的实现类都已经重写了 `hashCode` 和 `equals` 方法,自定义的类需要开发者自己重写这两个方法[^4]。 - **内部实现**:`HashSet` 内部使用 `HashMap` 来存储元素,`HashSet` 的元素作为 `HashMap` 的键,而 `HashMap` 的值则是一个固定的对象。`HashSet` 的操作实际上是适配到 `HashMap` 上完成的,例如 `HashSet` 的 `add` 方法通过 `HashMap` 的 `put` 方法来实现[^3][^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值