java set集合解析

java set集合解析

set

这里我们首先看到set接口
public interface Set<E> extends Collection<E>

注意一下官方对其的描述

 * A collection that contains no duplicate elements.  More formally, sets
 * contain no pair of elements <code>e1</code> and <code>e2</code> such that
 * <code>e1.equals(e2)</code>, and at most one null element.  As implied by
 * its name, this interface models the mathematical <i>set</i> abstraction.
 *

大致意思是Set是一个不能含有重复元素的collection,更准确的说其不能有重复元素,同时最多只能有一个空的元素。

下面是对set及其衍生类的介绍

* @param <E> the type of elements maintained by this set//由该set维护的元素
 *
 * @author  Josh Bloch
 * @author  Neal Gafter    //作者
 * @see Collection         //继承于collection
 * @see List               //衍生类
 * @see SortedSet          //排序的set接口
 * @see HashSet            //由hash值确定的set
 * @see TreeSet            //依据treeMap生成生成
 * @see AbstractSet        //一个通用的set模板
 * @see Collections#singleton(java.lang.Object)
 * @see Collections#EMPTY_SET
 * @since 1.2

Collection

我们接着看其继承的Collection的文档

public interface Collection<E> extends Iterable<E>

.The root interface in the <i>collection hierarchy</i>. A collection
* represents a group of objects, known as its <i>elements</i>. Some
* collections allow duplicate elements and others do not. Some are ordered
* and others unordered. The JDK does not provide any <i>direct</i>
* implementations of this interface: it provides implementations of more
* specific subinterfaces like <tt>Set</tt> and <tt>List</tt>. This interface
* is typically used to pass collections around and manipulate them where
* maximum generality is desired

大致的意思是这是集合层次的根接口,有些集合允许重复元素,而另一些则不允许。有些是有序的,有些是无序的。JDK没有直接提供任何接口的实现:它提供了更多的特定的子接口,如Set和List。这个接口通常用于传递集合并对其进行操作,最大通用性。

其实就是一个集合的根接口,这里通过封装一些方法,实现自己的方法,特性,同时也为后面的集合提供方便。

Iterable

可以看到这个接口同样继承于一个接口Iterable,原来还没有到底呀,我们接着看Iterable。

public interface Iterable<T>
这下终于到底了,接着我们看下官方对其的描述

* Implementing this interface allows an object to be the target of
 * the "for-each loop" statement.

继承这个接口实现for-each方法,也就是我们的遍历的方法,都知道当我们需要进行遍历的时候,需要直接或者间接继承
Iterable,同时对里面的Iterator iterator()方法进行重写,这也是自己实现集合中的遍历的方法。

既然set的关系都理清了,我们接着看下他的具体实现的类

AbstractSet

看过源码的应该都知道,如果说set是最基础的接口,定义了set的基本函数的话,那么AbstractSet 就是一个骨架
官方文档的描述。

 * This class provides a skeletal implementation of the <tt>Set</tt>
 * interface to minimize the effort required to implement this
 * interface. <p>

这个类提供了Set接口的框架实现,以最小化实现这个接口所需的工作量。也就是减轻工作量的效果。

这里列出里面实现的三个具体方法。

public boolean equals(Object o) {  //equals方法
        if (o == this)       //如果对象相同
            return true;

        if (!(o instanceof Set))     //如果不是set对象
            return false;
        Collection c = (Collection) o;    //强转为Collection,因为本身继承于AbstractCollection
        if (c.size() != size())         //如果长度不一样
            return false;
        try {
            return containsAll(c);       //再次通过函数判断
        } catch (ClassCastException unused)   {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }
    }
 public int hashCode() {
        int h = 0;
        Iterator<E> i = iterator();    //获取迭代器对象
        while (i.hasNext()) {          //遍历所有同时将所以元素的hashcode相加
            E obj = i.next();
            if (obj != null)
                h += obj.hashCode();
        }
        return h;
    }

`public boolean removeAll(Collection

HashSet

在上一篇中讲解了HashMap的实现,我们打开HashSet的源码

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

可以发现其继承于AbstractSet(一个set的骨架基类),同样的,其实现了set接口,Cloneable可复制接口,Serializable序列化接口。

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

可以发现HashSet的构造函数就是通过实例化一个value为Object的HashMap。
同样我们可以看到这里的iterator同样是使用了map中的keySet中的iterator

public Iterator<E> iterator() {
        return map.keySet().iterator();   //通过调用HashMap的keySet返回迭代器
    }

可以看到真正的实现了Iterator代码的复用,最终又是回到了Hashmap中的HashIterator中,同样实现了Iterator的操作

private abstract class HashIterator<E> implements Iterator<E> {//重写了Iterator
        HashMapEntry<K,V> next;        // next entry to return
        int expectedModCount;   // For fast-fail
        int index;              // current slot
        HashMapEntry<K,V> current;     // current entry

        HashIterator() {
            expectedModCount = modCount;
            if (size > 0) { // advance to first entry
                HashMapEntry[] t = table;
                while (index < t.length && (next = t[index++]) == null)
                    ;
            }
        }

        public final boolean hasNext() {
            return next != null;
        }

        final Entry<K,V> nextEntry() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            HashMapEntry<K,V> e = next;
            if (e == null)
                throw new NoSuchElementException();

            if ((next = e.next) == null) {
                HashMapEntry[] t = table;
                while (index < t.length && (next = t[index++]) == null)
                    ;
            }
            current = e;
            return e;
        }

        public void remove() {
            if (current == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            Object k = current.key;
            current = null;
            HashMap.this.removeEntryForKey(k);
            expectedModCount = modCount;
        }
    }

这里的add操作可以看到是通过HashMap的put操作完成的,同时是将一个value为PRESENT也就是Object的类添加进去,也就达到了只存储key的效果

private static final Object PRESENT = new Object();
public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

对于HashSet的遍历,因为上面返回了keyset,所以就不用多说了,相当于返回了一个只有key的set集合,可以直接进行迭代操作。

猜你喜欢

转载自blog.csdn.net/zxc641483573/article/details/79036542