Java 集合系列 16 HashSet

java 集合系列目录:

Java 集合系列 01 总体框架

Java 集合系列 02 Collection架构

Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例

Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例

Java 集合系列 05 Vector详细介绍(源码解析)和使用示例

Java 集合系列 06 Stack详细介绍(源码解析)和使用示例

Java 集合系列 07 List总结(LinkedList, ArrayList等使用场景和性能分析)

Java 集合系列 08 Map架构

Java 集合系列 09 HashMap详细介绍(源码解析)和使用示例

Java 集合系列 10 Hashtable详细介绍(源码解析)和使用示例

Java 集合系列 11 hashmap 和 hashtable 的区别

Java 集合系列 12 TreeMap

Java 集合系列 13 WeakHashMap

Java 集合系列 14 hashCode

Java 集合系列 15 Map总结

Java 集合系列 16 HashSet

Java 集合系列 17 TreeSet

概述

第1 部分 HashSet介绍 

  1.1 HashSet 简介

  1.2 HashSet的构造函数

  1.3 HashSet的主要API

第2 部分 HashSet数据结构

第3 部分 源码分析

第1 部分 HashSet介绍

1.1 HashSet 简介

  HashSet 是一个没有重复元素的集合。它是由HashMap实现的,不保证元素的顺序,而且HashSet允许使用 null 元素

HashSet是非同步的。如果多个线程同时访问一个哈希 set,而其中至少一个线程修改了该 set,那么它必须 保持外部同步。这通常是通过对自然封装该 set 的对象执行同步操作来完成的。如果不存在这样的对象,则应该使用 Collections.synchronizedSet 方法来“包装” set。最好在创建时完成这一操作,以防止对该 set 进行意外的不同步访问:

Set s = Collections.synchronizedSet(new HashSet(...));

1.2 HashSet的构造函数

// 默认构造函数
public HashSet() 

// 带集合的构造函数
public HashSet(Collection<? extends E> c) 

// 指定HashSet初始容量和加载因子的构造函数
public HashSet(int initialCapacity, float loadFactor) 

// 指定HashSet初始容量的构造函数
public HashSet(int initialCapacity) 

// 指定HashSet初始容量和加载因子的构造函数,dummy没有任何作用
HashSet(int initialCapacity, float loadFactor, boolean dummy)

1.3 HashSet的主要API

 boolean add(E e)
          如果此 set 中尚未包含指定元素,则添加指定元素。
 void clear()
          从此 set 中移除所有元素。
 Object clone()
          返回此 HashSet 实例的浅表副本:并没有复制这些元素本身。
 boolean contains(Object o)
          如果此 set 包含指定元素,则返回 true。
 boolean isEmpty()
          如果此 set 不包含任何元素,则返回 true。
 Iterator<E> iterator()
          返回对此 set 中元素进行迭代的迭代器。
 boolean remove(Object o)
          如果指定元素存在于此 set 中,则将其移除。
 int size()
          返回此 set 中的元素的数量(set 的容量)。 

第2 部分 HashSet数据结构

HashSet的继承关系如下:

java.lang.Object
   ?     java.util.AbstractCollection<E>
         ?     java.util.AbstractSet<E>
               ?     java.util.HashSet<E>

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable { }

HashSet与Map关系如下图:

从图中可以看出:
(01) HashSet继承于AbstractSet,并且实现了Set接口。
(02) HashSet的本质是一个"没有重复元素"的集合,它是通过HashMap实现的。HashSet中含有一个"HashMap类型的成员变量"map,HashSet的操作函数,实际上都是通过map实现的。

第3 部分 源码分析

  1 public class HashSet<E>
  2     extends AbstractSet<E>
  3     implements Set<E>, Cloneable, java.io.Serializable
  4 {
  5     static final long serialVersionUID = -5024744406713321676L;
  6
  7         // HashSet是通过map(HashMap对象)保存内容的
  8     private transient HashMap<E,Object> map;
  9
 10     // PRESENT是向map中插入key-value对应的value
 11     // 因为HashSet中只需要用到key,而HashMap是key-value键值对;
 12     // 所以,向map中添加键值对时,键值对的值固定是PRESENT
 13     private static final Object PRESENT = new Object();
 14
 15      // 默认构造函数
 16      //default initial capacity (16) and load factor (0.75)
 17     public HashSet() {
 18             // 调用HashMap的默认构造函数,创建map
 19         map = new HashMap<>();
 20     }
 21
 22     // 带集合的构造函数
 23     public HashSet(Collection<? extends E> c) {
 24             // 创建map。
 25         // 为什么要调用Math.max((int) (c.size()/.75f) + 1, 16),从 (c.size()/.75f) + 1 和 16 中选择一个比较大的树呢?
 26         // 首先,说明(c.size()/.75f) + 1
 27         //   因为从HashMap的效率(时间成本和空间成本)考虑,HashMap的加载因子是0.75。
 28         //   当HashMap的“阈值”(阈值=HashMap总的大小*加载因子) < “HashMap实际大小”时,
 29         //   就需要将HashMap的容量翻倍。
 30         //   所以,(c.size()/.75f) + 1 计算出来的正好是总的空间大小。
 31         // 接下来,说明为什么是 16 。
 32         //   HashMap的总的大小,必须是2的指数倍。若创建HashMap时,指定的大小不是2的指数倍;
 33         //   HashMap的构造函数中也会重新计算,找出比“指定大小”大的最小的2的指数倍的数。
 34         //   所以,这里指定为16是从性能考虑。避免重复计算。
 35         map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
 36         // 将集合(c)中的全部元素添加到HashSet中
 37         addAll(c);
 38     }
 39
 40     // 指定HashSet初始容量和加载因子的构造函数
 41     public HashSet(int initialCapacity, float loadFactor) {
 42         map = new HashMap<>(initialCapacity, loadFactor);
 43     }
 44
 45     // 指定HashSet初始容量的构造函数
 46     public HashSet(int initialCapacity) {
 47         map = new HashMap<>(initialCapacity);
 48     }
 49
 50     /**
 51      * Constructs a new, empty linked hash set.  (This package private
 52      * constructor is only used by LinkedHashSet.) The backing
 53      * HashMap instance is a LinkedHashMap with the specified initial
 54      * capacity and the specified load factor.
 55      *
 56      * @param      initialCapacity   the initial capacity of the hash map
 57      * @param      loadFactor        the load factor of the hash map
 58      * @param      dummy             ignored (distinguishes this
 59      *             constructor from other int, float constructor.)
 60      * @throws     IllegalArgumentException if the initial capacity is less
 61      *             than zero, or if the load factor is nonpositive
 62      */
 63      //以指定的initialCapacity和loadFactor构造一个新的空链接哈希集合。
 64      //dummy 为标识 该构造函数主要作用是对LinkedHashSet起到一个支持作用
 65     HashSet(int initialCapacity, float loadFactor, boolean dummy) {
 66         map = new LinkedHashMap<>(initialCapacity, loadFactor);
 67     }
 68
 69     // 返回HashSet的迭代器
 70     public Iterator<E> iterator() {
 71         return map.keySet().iterator();
 72     }
 73
 74     public int size() {
 75         return map.size();
 76     }
 77
 78     public boolean isEmpty() {
 79         return map.isEmpty();
 80     }
 81
 82     public boolean contains(Object o) {
 83         return map.containsKey(o);
 84     }
 85
 86     // 将元素(e)添加到HashSet中
 87     public boolean add(E e) {
 88         return map.put(e, PRESENT)==null;
 89     }
 90
 91     // 删除HashSet中的元素(o)
 92     public boolean remove(Object o) {
 93         return map.remove(o)==PRESENT;
 94     }
 95
 96     public void clear() {
 97         map.clear();
 98     }
 99
100     // 克隆一个HashSet,并返回Object对象
101     public Object clone() {
102         try {
103             HashSet<E> newSet = (HashSet<E>) super.clone();
104             newSet.map = (HashMap<E, Object>) map.clone();
105             return newSet;
106         } catch (CloneNotSupportedException e) {
107             throw new InternalError();
108         }
109     }
110
111     // java.io.Serializable的写入函数
112     // 将HashSet的“总的容量,加载因子,实际容量,所有的元素”都写入到输出流中
113     private void writeObject(java.io.ObjectOutputStream s)
114         throws java.io.IOException {
115         // Write out any hidden serialization magic
116         s.defaultWriteObject();
117
118         // Write out HashMap capacity and load factor
119         s.writeInt(map.capacity());
120         s.writeFloat(map.loadFactor());
121
122         // Write out size
123         s.writeInt(map.size());
124
125         // Write out all elements in the proper order.
126         for (E e : map.keySet())
127             s.writeObject(e);
128     }
129
130     // java.io.Serializable的读取函数
131     // 将HashSet的“总的容量,加载因子,实际容量,所有的元素”依次读出
132     private void readObject(java.io.ObjectInputStream s)
133         throws java.io.IOException, ClassNotFoundException {
134         // Read in any hidden serialization magic
135         s.defaultReadObject();
136
137         // Read in HashMap capacity and load factor and create backing HashMap
138         int capacity = s.readInt();
139         float loadFactor = s.readFloat();
140         map = (((HashSet)this) instanceof LinkedHashSet ?
141                new LinkedHashMap<E,Object>(capacity, loadFactor) :
142                new HashMap<E,Object>(capacity, loadFactor));
143
144         // Read in size
145         int size = s.readInt();
146
147         // Read in all elements in the proper order.
148         for (int i=0; i<size; i++) {
149             E e = (E) s.readObject();
150             map.put(e, PRESENT);
151         }
152     }
153 }
时间: 2024-10-14 04:23:57

Java 集合系列 16 HashSet的相关文章

Java 集合系列16之 HashSet详细介绍(源码解析)和使用示例

概要 这一章,我们对HashSet进行学习.我们先对HashSet有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashSet.内容包括:第1部分 HashSet介绍第2部分 HashSet数据结构第3部分 HashSet源码解析(基于JDK1.6.0_45)第4部分 HashSet遍历方式第5部分 HashSet示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3311252.html 第1部分 HashSet介绍 HashSet 简

【转】Java 集合系列16之 HashSet详细介绍(源码解析)和使用示例--不错

原文网址:http://www.cnblogs.com/skywang12345/p/3311252.html 概要 这一章,我们对HashSet进行学习.我们先对HashSet有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashSet.内容包括:第1部分 HashSet介绍第2部分 HashSet数据结构第3部分 HashSet源码解析(基于JDK1.6.0_45)第4部分 HashSet遍历方式第5部分 HashSet示例 转载请注明出处:http://www.cnblogs.

Java集合系列之HashSet源码分析

一.HashSet简介 HashSet是Set接口典型实现,它按照Hash算法来存储集合中的元素,具有很好的存取和查找性能.主要具有以下特点: 不保证set的迭代顺序 HashSet不是同步的,如果多个线程同时访问一个HashSet,要通过代码来保证其同步 集合元素值可以是null 当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据该值确定对象在HashSet中的存储位置.在Hash集合中,不能同时存放两个相等的

Java 集合系列16之 Spring Boot 配置文件 选项配置(一)

springboot配置选项(一) =================================================================== COMMON SPRING BOOT PROPERTIES This sample file is provided as a guideline . Do NOT copy it in its entirety to your own application. ^^^ ============================

Java 集合系列 17 TreeSet

java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例 Java 集合系列 05 Vector详细介绍(源码解析)和使用示例 Java 集合系列 06 Stack详细介绍(源码解析)和使用示例 Java 集合系列 07 List总结(LinkedList, ArrayList等使用场景和

【转】Java 集合系列目录(Category)

Java 集合系列目录(Category) 下面是最近总结的Java集合(JDK1.6.0_45)相关文章的目录. 01. Java 集合系列01之 总体框架 02. Java 集合系列02之 Collection架构 03. Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例 04. Java 集合系列04之 fail-fast总结(通过ArrayList来说明fail-fast的原理.解决办法) 05. Java 集合系列05之 LinkedList详细介绍(源码解析

Java 集合系列目录(Category)

Java 集合系列目录(Category) 转自:Java 集合系列目录(Category) 01. Java 集合系列01之 总体框架 02. Java 集合系列02之 Collection架构 03. Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例 04. Java 集合系列04之 fail-fast总结(通过ArrayList来说明fail-fast的原理.解决办法) 05. Java 集合系列05之 LinkedList详细介绍(源码解析)和使用示例 06. 

Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例

概要 这一章,我们对HashMap进行学习.我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap.内容包括:第1部分 HashMap介绍第2部分 HashMap数据结构第3部分 HashMap源码解析(基于JDK1.6.0_45)第3.1部分 HashMap的“拉链法”相关内容第3.2部分 HashMap的构造函数第3.3部分 HashMap的主要对外接口第3.4部分 HashMap实现的Cloneable接口第3.5部分 HashMap实现的Seria

Java 集合系列17之 TreeSet详细介绍(源码解析)和使用示例

概要 这一章,我们对TreeSet进行学习.我们先对TreeSet有个整体认识,然后再学习它的源码,最后再通过实例来学会使用TreeSet.内容包括:第1部分 TreeSet介绍第2部分 TreeSet数据结构第3部分 TreeSet源码解析(基于JDK1.6.0_45)第4部分 TreeSet遍历方式第5部分 TreeSet示例 转载请注明出处:http://www.cnblogs.com/skywang12345/admin/EditPosts.aspx?postid=3311268 第1部