HashSet
底层是HashMap
,故本文主要围绕HashMap
展开
HashSet 简述(不同之处)
核心成员变量
private transient HashMap<E,Object> map
,依托HashMap
实现功能。使用transient
对数据反序列化的理由同ArrayList
中的elementData
。- 由于扩容机制的存在(尤其是达到阈值就扩容),数组(
map
底层仍然是Node
型数组)内存在不少空元素是常见的情形。因此为了节省空间、提高性能,HashSet
也重写了序列化相关的writeObject()
和readObject()
方法,手动序列化和反序列化存入元素。
- 由于扩容机制的存在(尤其是达到阈值就扩容),数组(
private static final Object PRESENT = new Object();
,map
需要以键值对形式存入,故PRESENT
作为所有键的共同对应值,即起占位作用。
构造器
HashSet(Collection<? extends E> c)
,容量在集合大小的4/3倍和16之间取大值。addAll
方法是继承父类AbstractCollection
的同名方法,通过调用add()
方法将集合中的元素逐个加入。
这里笔者认为存在bug
,后续扩容机制中细说
这里由于HashMap
的相应构造器中调用了tableSizeFor
方法,故最终容量大小仍然是2的幂。具体见后文。
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
HashSet()
、HashSet(int initialCapacity)
、HashSet(int initialCapacity, float loadFactor)
底层为HashMap
,故略
成员方法
略
HashMap
entrySet
、keySet
、values
方法及它们用到的内部类EntrySet
、KeySet
、Values
,由于篇幅已单独成文。
https://blog.csdn.net/weixin_50934030/article/details/135348058
核心成员变量
transient Node<K,V>[] table
,用于存储键值对transient Set<Map.Entry<K,V>> entrySet
,实际运行类为HashMap.EntrySet
,为entrySet
方法服务transient Set<K> keySet
,实际运行类为HashMap.KeySet
,为keySet
方法服务transient Collection<V> values
,实际运行类为HashMap.Values
,为values
方法服务
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() {
return key; }
public final V getValue() {
return value; }
public final String toString() {
return key + "=" + value; }
//重写了hashCode方法
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue)