JDK1.8源码(八)——java.util.HashSet 类

  在上一篇博客,我们介绍了 Map 集合的一种典型实现 HashMap ,在 JDK1.8 中,HashMap 是由 数组+链表+红黑树构成,相对于早期版本的 JDK HashMap 实现,新增了红黑树作为底层数据结构,在数据量较大且哈希碰撞较多时,能够极大的增加检索的效率。了解 HashMap 的具体实现后,我们再来介绍由 HashMap 作为底层数据结构实现的一种数据结构——HashSet。(如果不了解 HashMap 的实现原理,建议先看看 HashMap,不然直接看 HashSet 是很难看懂的)

1、HashSet 定义

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

1 public class HashSet<E>
2     extends AbstractSet<E>
3     implements Set<E>, Cloneable, java.io.Serializable

  

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

2、字段属性

1 //HashSet集合中的内容是通过 HashMap 数据结构来存储的
2 private transient HashMap<E,Object> map;
3 //向HashSet中添加数据,数据在上面的 map 结构是作为 key 存在的,而value统一都是 PRESENT
4 private static final Object PRESENT = new Object();

  第一个定义一个 HashMap,作为实现 HashSet 的数据结构;第二个 PRESENT 对象,因为前面讲过 HashMap 是作为键值对 key-value 进行存储的,而 HashSet 不是键值对,那么选择 HashMap 作为实现,其原理就是存储在 HashSet 中的数据 作为 Map 的 key,而 Map 的value 统一为 PRESENT(下面介绍具体实现时会了解)。

3、构造函数

  ①、无参构造

1     public HashSet() {
2         map = new HashMap<>();
3     }

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

  ②、指定初始容量

1     public HashSet(int initialCapacity) {
2         map = new HashMap<>(initialCapacity);
3     }

  ③、指定初始容量和加载因子

1     public HashSet(int initialCapacity, float loadFactor) {
2         map = new HashMap<>(initialCapacity, loadFactor);
3     }

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

1     public HashSet(Collection<? extends E> c) {
2         map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
3         addAll(c);
4     }

  集合容量很好理解,这里我介绍一下什么是加载因子。在 HashMap 中,能够存储元素的数量就是:总的容量*加载因子 ,新增一个元素时,如果HashMap集合中的元素大于前面公式计算的结果了,那么就必须要进行扩容操作,从时间和空间考虑,加载因子一般都选默认的0.75。

4、添加元素

1     public boolean add(E e) {
2         return map.put(e, PRESENT)==null;
3     }

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

  也就是说 HashSet 的 add(E e) 方法,会将 e 作为 key,PRESENT 作为 value 插入到 map 集合中,如果 e 不存在,则插入成功返回 true;如果存在,则返回false。

5、删除元素

1     public boolean remove(Object o) {
2         return map.remove(o)==PRESENT;
3     }

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

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

6、查找元素

1     public boolean contains(Object o) {
2         return map.containsKey(o);
3     }

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

7、遍历元素

 1 HashSet<Integer> set = new HashSet<>();
 2 set.add(1);
 3 set.add(2);
 4 //增强for循环
 5 for(Integer i : set){
 6     System.out.println(i);
 7 }
 8 //普通for循环
 9 Iterator<Integer> iterator = set.iterator();
10 while (iterator.hasNext()){
11     System.out.println(iterator.next());
12 }

原文地址:https://www.cnblogs.com/ysocean/p/9809046.html

时间: 2024-10-29 04:39:26

JDK1.8源码(八)——java.util.HashSet 类的相关文章

JDK1.8源码(七)——java.util.HashMap 类

本篇博客我们来介绍在 JDK1.8 中 HashMap 的源码实现,这也是最常用的一个集合.但是在介绍 HashMap 之前,我们先介绍什么是 Hash表. 1.哈希表 Hash表也称为散列表,也有直接译作哈希表,Hash表是一种根据关键字值(key - value)而直接进行访问的数据结构.也就是说它通过把关键码值映射到表中的一个位置来访问记录,以此来加快查找的速度.在链表.数组等数据结构中,查找某个关键字,通常要遍历整个数据结构,也就是O(N)的时间级,但是对于哈希表来说,只是O(1)的时间

JDK1.8源码(五)——java.util.ArrayList 类

关于 JDK 的集合类的整体介绍可以看这张图,本篇博客我们不系统的介绍整个集合的构造,重点是介绍 ArrayList 类是如何实现的. 1.ArrayList 定义 ArrayList 是一个用数组实现的集合,支持随机访问,元素有序且可以重复. public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializabl

JDK1.8源码(六)——java.util.LinkedList 类

上一篇博客我们介绍了List集合的一种典型实现 ArrayList,我们知道 ArrayList 是由数组构成的,本篇博客我们介绍 List 集合的另一种典型实现 LinkedList,这是一个由链表构成的数组,关于链表的介绍,在这篇博客中 我们也详细介绍过,本篇博客我们将介绍 LinkedList 是如何实现的. 1.LinkedList 定义 LinkedList 是一个用链表实现的集合,元素有序且可以重复. 1 public class LinkedList<E> 2 extends A

源码(03) -- java.util.Collection&lt;E&gt;

 java.util.Collection<E> 源码分析 --------------------------------------------------------------------------------- java.util.Collection<E>是一个接口,它的定义如下: 1 public interface Collection<E> extends Iterable<E> { 2 // Query Operations 3 //

源码(06) -- java.util.AbstractList&lt;E&gt;

java.util.AbstractList<E> 源码分析(JDK1.7) --------------------------------------------------------------------------------- java.util.AbstractList<E>是一个抽象类,它的定义如下: 1 public abstract class AbstractList<E> extends AbstractCollection<E>

源码(08) -- java.util.ListIterator&lt;E&gt;

java.util.ListIterator<E> 源码分析(JDK1.7) --------------------------------------------------------------------------------- java.util.ListIterator<E>是一个接口,它的定义如下: 1 package java.util; 2 3 4 public interface ListIterator<E> extends Iterator&

源码(07) -- java.util.Iterator&lt;E&gt;

java.util.Iterator<E> 源码分析(JDK1.7) --------------------------------------------------------------------------------- java.util.Iterator<E>是一个接口,它的定义如下: 1 public interface Iterator<E> { 2 3 boolean hasNext(); 4 5 E next(); 6 7 void remove

java源码(4) -- java.util.Collection

我也不知道看源码有什么用,就是想去看看... java.util.Collection 这是一个接口,是java中集合框架的根接口. 下面来具体看看该接口中定义了哪些方法 public interface Collection<E> extends Iterable<E>{ //操作集合元素的方法 boolean add(E e);//将元素E添加到该集合中 boolean addAll(Collection<? extends E> c);//将集合c添加到该集合中

Java源码之 java.util.concurrent 学习笔记01

准备花点时间看看 java.util.concurrent这个包的源代码,来提高自己对Java的认识,努力~~~ 参阅了@梧留柒的博客!边看源码,边通过前辈的博客学习! 包下的代码结构分类: 1.java.util.concurrent.atomic,正如它的英文意思一样,是一个线程安全.原子操作相关的包 另一个专门为线程安全设计的Java包,包含多个原子操作类.这个包里面提供了一组原子变量类.其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程