Java源码初学_HashSet&LinkedHashSet

时间:2020-11-27 17:58:03

一.概述

  HashSet是建立在HashMap的基础上的,其内部存在指向一个HashMap对象的引用,操作HashSet实际上就是操作HashMap,而HashMap中所有键的值都指向一个叫做Dummy value的值.这是一个Object对象.是在HashSet进行显示初始化的时候初始化出来的,而HashMap在构造函数中被创建出来.
二.HashMap在HashSet方法中的使用及LinkedHashMap
  HashSet是建立在HashMap的基础上的,它的几乎所有的操作都是通过HashMap完成对于key的操作来实现的,通过add方法可以得知,这个HashMap所有的键都指向一个值.

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
    static final long serialVersionUID = -5024744406713321676L;
    //存储键值对的Map.这个Map将不会被序列化
    private transient HashMap<E,Object> map;

    // Dummy value 
    private static final Object PRESENT = new Object();

    public HashSet() {
    map = new HashMap<E,Object>();
    }

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

    public HashSet(int initialCapacity, float loadFactor) {
    map = new HashMap<E,Object>(initialCapacity, loadFactor);
    }

    public HashSet(int initialCapacity) {
    map = new HashMap<E,Object>(initialCapacity);
    }
    //LinkedHashSet的实现关键
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
    }

    public Iterator<E> iterator() {
    return map.keySet().iterator();
    }

    public int size() {
    return map.size();
    }

    public boolean isEmpty() {
    return map.isEmpty();
    }

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

    public boolean add(E e) {
    //放入元素和present的键值对
    return map.put(e, PRESENT)==null;
    }

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

    public void clear() {
    map.clear();
    }

   有两点需要注意的,第一点,这个Map是不会序列化的,因此在写入文件的时候,除了写入文件HashSet的信息以外,还写入map的容量(capacity),装填因子(loadFactor)以及元素数目(size),然后在从文件读取的时候,先创建map,然后依次从map中装填key的信息.代码如下:

private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
    s.defaultWriteObject();

        s.writeInt(map.capacity());
        s.writeFloat(map.loadFactor());

        s.writeInt(map.size());

    for (Iterator i=map.keySet().iterator(); i.hasNext(); )
            s.writeObject(i.next());
    }

    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
    s.defaultReadObject();

        int capacity = s.readInt();
        float loadFactor = s.readFloat();
        map = (((HashSet)this) instanceof LinkedHashSet ?
               new LinkedHashMap<E,Object>(capacity, loadFactor) :
               new HashMap<E,Object>(capacity, loadFactor));

        int size = s.readInt();

    for (int i=0; i<size; i++) {
            E e = (E) s.readObject();
            map.put(e, PRESENT);
        }
    }

    第二点,HashSet中有一个不是公共的有boolean类型的参数的构造方法,它供LinkedHashSet调用.可以将LinkedHashSet内置的Map引用初始化为LinkedHashMap对象.(注意LinkedHashSet无法实现按照访问顺序排序).