当前位置:天才代写 > tutorial > JAVA 教程 > Java荟萃进修(十六) HashSet具体先容(源码理会)和利用示例

Java荟萃进修(十六) HashSet具体先容(源码理会)和利用示例

2017-11-02 08:00 星期四 所属: JAVA 教程 浏览:49

副标题#e#

这一章,我们对HashSet举办进修。
我们先对HashSet有个整体认识,然后再进修它的源码,最后再通过实例来学会利用HashSet。

第1部门 HashSet先容

HashSet 简介

HashSet 是一个没有反复元素的荟萃。
它是由HashMap实现的,不担保元素的顺序,并且HashSet答允利用 null 元素。
HashSet长短同步的。假如多个线程同时会见一个哈希 set,而个中至少一个线程修改了该 set,那么它必需 保持外部同步。这凡是是通过对自然封装该 set 的工具执行同步操纵来完成的。假如不存在这样的工具,则应该利用 Collections.synchronizedSet 要领来“包装” set。最亏得建设时完成这一操纵,以防备对该 set 举办意外的差异步会见:

Set s = Collections.synchronizedSet(new HashSet(…));

HashSet通过iterator()返回的迭代器是fail-fast的。

HashSet的担任干系如下:

java.lang.Object
        java.util.AbstractCollection<E>
              java.util.AbstractSet<E>
                    java.util.HashSet<E>
     
public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable { }

HashSet与Map干系如下图:

Java聚集学习(十六) HashSet详细介绍(源码剖析)和操作示例

查察本栏目

HashSet的结构函数

// 默认结构函数
public HashSet() 
     
// 带荟萃的结构函数
public HashSet(Collection<? extends E> c) 
     
// 指定HashSet初始容量和加载因子的结构函数
public HashSet(int initialCapacity, float loadFactor) 
     
// 指定HashSet初始容量的结构函数
public HashSet(int initialCapacity) 
     
// 指定HashSet初始容量和加载因子的结构函数,dummy没有任何浸染
HashSet(int initialCapacity, float loadFactor, boolean dummy)

HashSet的主要API

boolean         add(E object)
void            clear()
Object          clone()
boolean         contains(Object object)
boolean         isEmpty()
Iterator<E>     iterator()
boolean         remove(Object object)
int             size()

第2部门 HashSet源码理会

为了更相识HashSet的道理,下面临HashSet源码代码作出阐明。

package java.util;
     
public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
    static final long serialVersionUID = -5024744406713321676L;
     
    // HashSet是通过map(HashMap工具)生存内容的
    private transient HashMap<E,Object> map;
     
    // PRESENT是向map中插入key-value对应的value
    // 因为HashSet中只需要用到key,而HashMap是key-value键值对;
    // 所以,向map中添加键值对时,键值对的值牢靠是PRESENT
    private static final Object PRESENT = new Object();
     
    // 默认结构函数
    public HashSet() {
        // 挪用HashMap的默认结构函数,建设map
        map = new HashMap<E,Object>();
    }
     
    // 带荟萃的结构函数
    public HashSet(Collection<? extends E> c) {
        // 建设map。
        // 为什么要挪用Math.max((int) (c.size()/.75f) + 1, 16),从 (c.size()/.75f) + 1 和 16 中选择一个较量大的树呢?        
        // 首先,说明(c.size()/.75f) + 1
        //   因为从HashMap的效率(时间本钱和空间本钱)思量,HashMap的加载因子是0.75。
        //   当HashMap的“阈值”(阈值=HashMap总的巨细*加载因子) < “HashMap实际巨细”时,
        //   就需要将HashMap的容量翻倍。
        //   所以,(c.size()/.75f) + 1 计较出来的正好是总的空间巨细。
        // 接下来,说明为什么是 16 。
        //   HashMap的总的巨细,必需是2的指数倍。若建设HashMap时,指定的巨细不是2的指数倍;
        //   HashMap的结构函数中也会从头计较,找出比“指定巨细”大的最小的2的指数倍的数。
        //   所以,这里指定为16是从机能思量。制止反复计较。
        map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
        // 将荟萃(c)中的全部元素添加到HashSet中
        addAll(c);
    }
     
    // 指定HashSet初始容量和加载因子的结构函数
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<E,Object>(initialCapacity, loadFactor);
    }
     
    // 指定HashSet初始容量的结构函数
    public HashSet(int initialCapacity) {
        map = new HashMap<E,Object>(initialCapacity);
    }
     
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
    }
     
    // 返回HashSet的迭代器
    public Iterator<E> iterator() {
        // 实际上返回的是HashMap的“key荟萃的迭代器”
        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);
    }
     
    // 将元素(e)添加到HashSet中
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
     
    // 删除HashSet中的元素(o)
    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }
     
    public void clear() {
        map.clear();
    }
     
    // 克隆一个HashSet,并返回Object工具
    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();
        }
    }
     
    // java.io.Serializable的写入函数
    // 将HashSet的“总的容量,加载因子,实际容量,所有的元素”都写入到输出流中
    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 (Iterator i=map.keySet().iterator(); i.hasNext(); )
            s.writeObject(i.next());
    }
     
     
    // java.io.Serializable的读取函数
    // 将HashSet的“总的容量,加载因子,实际容量,所有的元素”依次读出
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // Read in any hidden serialization magic
        s.defaultReadObject();
     
        // Read in HashMap capacity and load factor and create backing HashMap
        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));
     
        // Read in size
        int size = s.readInt();
     
        // Read in all elements in the proper order.
        for (int i=0; i<size; i++) {
            E e = (E) s.readObject();
            map.put(e, PRESENT);
        }
    }
}

说明:


#p#副标题#e#

#p#分页标题#e#

HashSet的代码实际上很是简朴,通过上面的注释应该很可以或许看懂。它是通过HashMap实现的,若对HashSet的领略有坚苦,发起先进修以下HashMap;学完HashMap之后,在进修HashSet就很是容易了。

第3部门 HashSet遍历方法

3.1 通过Iterator遍历HashSet

第一步:按照iterator()获取HashSet的迭代器。
第二步:遍历迭代器获取各个元素。

// 假设set是HashSet工具
for(Iterator iterator = set.iterator();
      iterator.hasNext(); ) {
   iterator.next();
}  

3.2 通过for-each遍历HashSet

第一步:按照toArray()获取HashSet的元素荟萃对应的数组。
第二步:遍历数组,获取各个元素。

// 假设set是HashSet工具,而且set中元素是String范例
String[] arr = (String[])set.toArray(new String[0]);
for (String str:arr)
   System.out.printf("for each : %s\n", str);

HashSet的遍历测试措施如下:

import java.util.Random;
import java.util.Iterator;
import java.util.HashSet;
     
/*
 * @desc 先容HashSet遍历要领
 *
 * @author skywang
 */
public class HashSetIteratorTest {
     
    public static void main(String[] args) {
        // 新建HashSet
        HashSet set = new HashSet();
     
        // 添加元素 到HashSet中
        for (int i=0; i<5; i++)
            set.add(""+i);
     
        // 通过Iterator遍历HashSet
        iteratorHashSet(set) ;
     
        // 通过for-each遍历HashSet
        foreachHashSet(set);
    }
     
    /*
     * 通过Iterator遍历HashSet。推荐方法
     */
    private static void iteratorHashSet(HashSet set) {
        for(Iterator iterator = set.iterator();
               iterator.hasNext(); ) {
            System.out.printf("iterator : %s\n", iterator.next());
        }
    }
     
    /*
     * 通过for-each遍历HashSet。不推荐!此要领需要先将Set转换为数组
     */
    private static void foreachHashSet(HashSet set) {
        String[] arr = (String[])set.toArray(new String[0]);
        for (String str:arr)
            System.out.printf("for each : %s\n", str);
    }
}

第4部门 HashSet示例

#p#分页标题#e#

下面我们通过实例进修如何利用HashSet

import java.util.Iterator;
import java.util.HashSet;
     
/*
 * @desc HashSet常用API的利用。
 *
 * @author skywang
 */
public class HashSetTest {
     
    public static void main(String[] args) {
        // HashSet常用API
        testHashSetAPIs() ;
    }
     
    /*
     * HashSet除了iterator()和add()之外的其它常用API
     */
    private static void testHashSetAPIs() {
        // 新建HashSet
        HashSet set = new HashSet();
     
        // 将元素添加到Set中
        set.add("a");
        set.add("b");
        set.add("c");
        set.add("d");
        set.add("e");
     
        // 打印HashSet的实际巨细
        System.out.printf("size : %d\n", set.size());
     
        // 判定HashSet是否包括某个值
        System.out.printf("HashSet contains a :%s\n", set.contains("a"));
        System.out.printf("HashSet contains g :%s\n", set.contains("g"));
     
        // 删除HashSet中的“e”
        set.remove("e");
     
        // 将Set转换为数组
        String[] arr = (String[])set.toArray(new String[0]);
        for (String str:arr)
            System.out.printf("for each : %s\n", str);
     
        // 新建一个包括b、c、f的HashSet
        HashSet otherset = new HashSet();
        otherset.add("b");
        otherset.add("c");
        otherset.add("f");
     
        // 克隆一个removeset,内容和set一模一样
        HashSet removeset = (HashSet)set.clone();
        // 删除“removeset中,属于otherSet的元素”
        removeset.removeAll(otherset);
        // 打印removeset
        System.out.printf("removeset : %s\n", removeset);
     
        // 克隆一个retainset,内容和set一模一样
        HashSet retainset = (HashSet)set.clone();
        // 保存“retainset中,属于otherSet的元素”
        retainset.retainAll(otherset);
        // 打印retainset
        System.out.printf("retainset : %s\n", retainset);
     
     
        // 遍历HashSet
        for(Iterator iterator = set.iterator();
               iterator.hasNext(); ) 
            System.out.printf("iterator : %s\n", iterator.next());
     
        // 清空HashSet
        set.clear();
     
        // 输出HashSet是否为空
        System.out.printf("%s\n", set.isEmpty()?"set is empty":"set is not empty");
    }
     
}

 

    关键字:


天才代写-代写联系方式