HashSet是一个依赖于HashMap的Set接口实现,容器的元素存储和操做都是基于内部的一个HashMap实例实现,由于这个缘由,它不保证Set中元素的迭代顺序特别是不保证该顺序的恒久不变,容许插入null元素。该类能够为基本的集合操做提供稳定的性能保证,这些基本操做包括add、remove、contains和size,假定哈希函数正确地将元素分布在底层HashMap的槽中,那么对此HashSet进行迭代所需的时间与元素的个数和底层HashMap的槽的个数成正比的,因此迭代性能很重要的话,就不要将初始容量设置得过高(或者负载因子设置得过低)。注意HashSet不是线程安全的容器,若是有多个线程访问该容器,且至少有一个线程对容器作告终构性修改,那么它就必须在外部保证同步,这一般是经过对操做该容器的代码块加锁实现的,若是没有则可使用Collections.synchronizedSet在包装它做为一个线程安全的容器使用。HashSet的iterator返回的迭代器对象Iterator是fail-fast(快速失败)的,如何理解,即在该迭代器建立以后任什么时候间对该容器作告终构性修改(除了基于iterator.remve方法删除容器元素以外)都将致使迭代器遍历时抛出ConcurrentModificationException异常,这种快速失败行为没法绝对保证,所以依赖于这个特性编写应用程序是错误的。java
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable { static final long serialVersionUID = -5024744406713321676L; //底层的HashMap实例,这个对象是HashSet的核心 private transient HashMap<E,Object> map; //HashSet的元素其实就是保存在HashMap实例的KeySet集合里,key/value键值对中的value就直接保存它这个固定的对象 private static final Object PRESENT = new Object(); }
HashSet继承自AbstractSet类,该类实现了一些集合和Set基本操做方法,实现了Set接口在这里几乎起的相似代码注释的功能,由于AbstractSet自己已经实现了Set接口,经过继承它HashSet也间接实现了Set接口,此外HashSet也实现了Clonable接口支持对象的clone()方法拷贝,实现了java.io.Serializable代表该类也支持序列化安全
/** * 构造函数,底层的HashMap实例默认的初始容量16,负载因子0.75 */ public HashSet() { map = new HashMap<>(); } /** * 构造函数,在初始化实例时将指定容器的全部元素插入容器中,底层HashMap实例默认负载因子0.75,初始化容量取基于负载 * 因子计算的容器容量和默认初始容量的较大值 */ public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } /** * 构造函数,为底层HashMap指定初始容量和加载因子 */ public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } /** * 构造函数,为底层HashMap指定初始容量,,加载因子默认0.75 */ public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } /** * 构造函数,该方法属于包私有的方法仅被LinkedHashSet使用,dummy参数仅仅只是为了和第三个构造方法(底层是HashMap * 实例)作区分 */ HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }
public boolean isEmpty() { return map.isEmpty(); }
很简单容器的元素都保存在底层的HashMap实例中,因此直接判断底层HashMap实例是否为空。数据结构
public boolean add(E e) { return map.put(e, PRESENT)==null; }
分析方法源码可知HashSet添加元素实际也是调用底层HashMap的put方法,将元素保存在底层HashMap实例的键值对key/value的key中函数
public boolean remove(Object o) { return map.remove(o)==PRESENT; }
同样也是直接调用底层HashMap的remove方法删除元素o源码分析
//返回容器迭代器,无序 public Iterator<E> iterator() { return map.keySet().iterator(); } /** * 返回容器保存的元素个数 */ public int size() { return map.size(); } /** * 返回容器是否为空 */ public boolean isEmpty() { return map.isEmpty(); } /** * 若是容器包含对象o返回true不然返回false */ public boolean contains(Object o) { return map.containsKey(o); } public Object clone() { try { HashSet<E> newSet = (HashSet<E>) super.clone(); newSet.map = (HashMap<E, Object>) map.clone(); return newSet; } catch (CloneNotSupportedException e) { throw new InternalError(e); } } /** * 序列化时调用保存对象状态 */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Write out any hidden serialization magic s.defaultWriteObject(); // Write out HashMap capacity and load factor s.writeInt(map.capacity()); s.writeFloat(map.loadFactor()); // Write out size s.writeInt(map.size()); // Write out all elements in the proper order. for (E e : map.keySet()) s.writeObject(e); } /** * 反序列时调用 */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in any hidden serialization magic s.defaultReadObject(); // Read capacity and verify non-negative. int capacity = s.readInt(); if (capacity < 0) { throw new InvalidObjectException("Illegal capacity: " + capacity); } // Read load factor and verify positive and non NaN. float loadFactor = s.readFloat(); if (loadFactor <= 0 || Float.isNaN(loadFactor)) { throw new InvalidObjectException("Illegal load factor: " + loadFactor); } // Read size and verify non-negative. int size = s.readInt(); if (size < 0) { throw new InvalidObjectException("Illegal size: " + size); } capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f), HashMap.MAXIMUM_CAPACITY); SharedSecrets.getJavaOISAccess() .checkArray(s, Map.Entry[].class, HashMap.tableSizeFor(capacity)); // Create backing HashMap map = (((HashSet<?>)this) instanceof LinkedHashSet ? new LinkedHashMap<E,Object>(capacity, loadFactor) : new HashMap<E,Object>(capacity, loadFactor)); // Read in all elements in the proper order. for (int i=0; i<size; i++) { @SuppressWarnings("unchecked") E e = (E) s.readObject(); map.put(e, PRESENT); } } /** * 返回一个延迟绑定的迭代器 */ public Spliterator<E> spliterator() { return new HashMap.KeySpliterator<E,Object>(map, 0, -1, 0, 0); }
HashSet底层实现依赖于对象内部的一个HashMap实例,容器元素最终是以键值对key的形式保存在底层HashMap实例中,HashSet容器的全部操做实际操做的都是底层的HashMap实例性能