JDK1.6之HashSet详解

一、HashSet概述

HashSet是Set接口的一个实现类。
??HashSet继承了AbstractSet,实现了Set,它是一个集合,支持相关的添加、删除、修改、遍历等功能。
??HashSet实现了Cloneable接口,能被克隆。
??HashSet实现了Serializable接口,这意味着Serializable支持序列化,能通过序列化去传输。
??HashSet底层是由HashMap实现的,其功能基本都是调用HashMap的相关接口来实现的。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
??HashSet是不同步的

二、HashSet源码

??HashSet源码中最先出现的是定义了一个变量:

1
    transient HashMap<E, HashSet<E>> backingMap;

??从这个变量的声明可以看出,HashSet实际上是由HashMap实现的,并且不用序列化。

2.1 构造方法

??HashSet有4个公外部使用的构造方法:无参构造方法、指定初始容量的构造方法、指定初始容量和增长因子的构造方法和参数为collection的构造方法。在构造方法中,默认的初始容量是16,加载因子是 0.75。
??public HashSet(),构造一个空的HashMap,源码如下:

1
2
3
4
5
6
    public HashSet() {
        this(new HashMap<E, HashSet<E>>());
    }
    HashSet(HashMap<E, HashSet<E>> backingMap) {
        this.backingMap = backingMap;
    }

??public HashSet(int capacity),创建一个具有初始容量的HashMap,源码如下:

1
2
3
    public HashSet(int capacity) {
        this(new HashMap<E, HashSet<E>>(capacity));
    }

??public HashSet(int capacity, float loadFactor),创建初始容量和增长因子的HashMap,源码如下:

1
2
3
    public HashSet(int capacity, float loadFactor) {
        this(new HashMap<E, HashSet<E>>(capacity, loadFactor));
    }

??public HashSet(Collection collection),参数为collection的构造方法,源码如下:

1
2
3
4
5
6
7
    public HashSet(Collection<? extends E> collection) {
        this(new HashMap<E, HashSet<E>>(collection.size() < 6 ? 11 : collection
                .size() * 2));
        for (E e : collection) {
            add(e);
        }
    }

??从上面代码可以看出,该方法的实现是:先创建一个具有初始容量的HashMap,这个初始容量取决于collection的元素数量;然后将collection中的元素挨个添加到HashMap中。

2.2 其他方法

??public boolean add(E object),添加元素,源码如下:

1
2
3
    public boolean add(E object) {
        return backingMap.put(object, this) == null;
    }

??public void clear(),清空HashSet,源码如下:

1
2
3
    public void clear() {
        backingMap.clear();
    }

??public Object clone(),返回HashSet的浅克隆对象。
??public boolean contains(Object object),判断是否包含某个元素,源码如下:

1
2
3
    public boolean contains(Object object) {
        return backingMap.containsKey(object);
    }

??从这个方法能看出HashSet中的对象是保存在HashMap的key中的,HashM的value保存的是常量。
??public boolean isEmpty(),判断当前HashSet是否为空,源码如下:

1
2
3
    public boolean isEmpty() {
        return backingMap.isEmpty();
    }

??public Iterator iterator(),返回迭代器,源码如下:

1
2
3
    public Iterator<E> iterator() {
        return backingMap.keySet().iterator();
    }

??public boolean remove(Object object),移除元素,源码如下:

1
2
3
    public boolean remove(Object object) {
        return backingMap.remove(object) != null;
    }

??public int size(),返回HashSet中的元素数量,源码如下:

1
2
3
    public int size() {
        return backingMap.size();
    }

??private void writeObject(ObjectOutputStream stream),将HashSet中的数据写入到输入流中,源码如下:

1
2
3
4
5
6
7
8
9
    private void writeObject(ObjectOutputStream stream) throws IOException {
        stream.defaultWriteObject();
        stream.writeInt(backingMap.table.length);
        stream.writeFloat(HashMap.DEFAULT_LOAD_FACTOR);
        stream.writeInt(size());
        for (E e : this) {
            stream.writeObject(e);
        }
    }

??从上面代码可以看出,该方法的实现是:先写容量,再写增长因子,最后写具体的数据。
??private void readObject(ObjectInputStream stream),从输入流中读取数据,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
    private void readObject(ObjectInputStream stream) throws IOException,
            ClassNotFoundException {
        stream.defaultReadObject();
        int length = stream.readInt();
        float loadFactor = stream.readFloat();
        backingMap = createBackingMap(length, loadFactor);
        int elementCount = stream.readInt();
        for (int i = elementCount; --i >= 0;) {
            E key = (E) stream.readObject();
            backingMap.put(key, this);
        }
    }

??从上面代码可以看出,该方法的实现是:先读取容量,再读增长因子,最后读取数据。

三、HashSet遍历

??HashSet常用的遍历方法有2种:Iterator遍历和foreach循环。
??测试代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        Set<String> hashSetTest = new HashSet<String>();
        hashSetTest.add("看书");
        hashSetTest.add("看电影");
        hashSetTest.add("看电视剧");
        hashSetTest.add("看综艺");
       
        System.out.println("迭代器遍历结果:");
        Iterator<String> it = hashSetTest.iterator();
        while (it.hasNext()) {
          System.out.println(it.next());
        }
       
        System.out.println("foreach循环遍历结果:");
        for (String str : hashSetTest) {
          System.out.println(str);
        }

??测试结果如下:

迭代器遍历结果:
看书
看综艺
看电影
看电视剧
foreach循环遍历结果:
看书
看综艺
看电影
看电视剧