Java中的HashSet的定义以及用法

作者: Arvin Chen 分类: Java 来源: Break易站(www.breakyizhan.com)
  •   Java 集合框架

    HashSet的定义

    HashSet类实现了Set接口,由一个实际上是HashMap实例的散列表​​支持。不能保证该集合的迭代次序,这意味着该类不能保证元素随时间的不变顺序。这个类允许null元素。该类还为基本操作(如添加,删除,包含和大小)提供了恒定的时间性能,假定散列函数将元素正确地分散到桶中,我们将在文章中进一步讨论。
    HashSet的一些重要特性是:

    • 实现Set Interface。
    • HashSet的基础数据结构是散列表。
    • 由于它实现了Set Interface,所以不允许重复值。
    • 您在HashSet中插入的对象不保证以相同顺序插入。对象基于其哈希码插入。
    • HashSet中允许使用NULL元素。
    • HashSet还实现了Searlizable和Cloneable接口。

    现在为了维持恒定的时间性能,迭代HashSet需要的时间与HashSet实例的大小(元素数量)加上支持HashMap实例的“容量”(桶的数量)的总和成正比。因此,如果迭代性能很重要,不要将初始容量设置得太高(或者负载因子太低)是非常重要的。

    初始容量:初始容量意味着在创建散列表(HashSet内部使用散列表数据结构)时创建桶的数量。如果当前尺寸变满,桶的数量将自动增加。
    负载因数:负载因数是衡量HashSet在其容量自动增加之前能够获得的满量程。当哈希表中的条目数量超过负载因子和当前容量的乘积时,散列表就会被重新映射(即重建内部数据结构),以便散列表大约是存储桶数量的两倍。

                      表格中存储的元素数量
       加载因子= -----------------------------------------
                            散列表的大小 
    

    示例:如果内部容量为16并且加载因子为0.75,那么当表中有12个元素时,桶的数量会自动增加。


    对性能的影响:
    负载因子和初始容量是影响HashSet操作性能的两个主要因素。0.75的负载因子在时间和空间复杂度方面提供了非常有效的性能。如果我们将负载因子值增加得超过这个值,那么内存开销将会减少(因为它会减少内部重建操作),但是它会影响哈希表中的添加和搜索操作。为了减少重新哈希操作,我们应该明智地选择初始容量。如果初始容量大于最大入口数量除以负载因子,则不会发生重新刷新操作。

    注:HashSet中的实现不同步,因为如果多个线程同时访问散列集,并且至少有一个线程修改了该集,它必须在外部同步。这通常是通过在自然封装集合的某个对象上进行同步来完成的。如果不存在这样的对象,则应该使用Collections.synchronizedSet方法来“包装”该集合。这最好在创建时完成,以防止意外的不同步访问集合,如下所示:

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

    HashSet中的构造函数:

    1. HashSet h = new HashSet(); 
      默认初始容量为16,默认加载因子为0.75。
    2. HashSet h = new HashSet(int initialCapacity); 
      默认的0.75的loadFactor
    3. HashSet h = new HashSet(int initialCapacity,float loadFactor);
    4. HashSet h = new HashSet(Collection C);

    下面的程序说明了HashSet的几个基本操作:

    // Java program to demonstrate working of HashSet
    import java.util.*;
    
    class Test
    {
        public static void main(String[]args)
        {
            HashSet<String> h = new HashSet<String>();
    
            // Adding elements into HashSet usind add()
            h.add("India");
            h.add("Australia");
            h.add("South Africa");
            h.add("India");// adding duplicate elements
    
            // Displaying the HashSet
            System.out.println(h);
            System.out.println("List contains India or not:" +
                               h.contains("India"));
    
            // Removing items from HashSet using remove()
            h.remove("Australia");
            System.out.println("List after removing Australia:"+h);
    
            // Iterating over hash set items
            System.out.println("Iterating over list:");
            Iterator<String> i = h.iterator();
            while (i.hasNext())
                System.out.println(i.next());
        }
    }
    

    输出:

    [South Africa, Australia, India]
    List contains India or not:true
    List after removing Australia:[South Africa, India]
    Iterating over list:
    South Africa
    India

    HashSet的内部工作
    由Map内部备份的所有Set接口类。HashSet使用HashMap在内部存储它的对象。您一定想知道,要在HashMap中输入值,我们需要一个键值对,但在HashSet中,我们只传递一个值。

    存储在HashMap中
    实际上,我们在HashSet中插入的值作为映射对象的关键字,并且其值java使用常量变量。所以在键值对中,所有键都具有相同的值。

    在java文档中实现HashSet

    private transient HashMap map;
    
    //构造函数 -  1
    //所有的构造函数都在内部创建HashMap对象。
    public HashSet()
    {
        //创建内部支持HashMap对象
        map = new HashMap();
    }
    
    //构造函数 -  2
    public HashSet(int initialCapacity)
    {
        //创建内部支持HashMap对象
        map = new HashMap(initialCapacity);
    }
    
    //与map中的对象关联的虚拟值
    private static final Object PRESENT = new Object();
    

    如果我们看一下HashSet类的add()方法:

    public boolean add(E e)
    {
       return map.put(e,PRESENT)== null;
    }
    

    我们可以注意到,HashSet类的add()方法通过传递指定的元素作为键和常量“PRESENT”作为其值,来内部调用支持HashMap对象的put()方法。

    remove()方法也以相同的方式工作。它内部调用Map接口的remove方法。

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

    HashSet操作的时间复杂度:HashSet的基础数据结构是散列表。因此,对于添加,移除和查找(包含方法)操作,HashSet需要O(1)次的时间复杂度(平均或通常情况下)的时间复杂度。

    HashSet中的方法:

    1. boolean add(E e):用于添加指定元素(如果不存在),如果存在则返回false。
    2. void clear():用于删除set中的所有元素。
    3. boolean contains(Object o): 如果元素存在于set中,则返回true。
    4. boolean remove(Object o):用于删除元素,如果它存在于set中。
    5. Iterator iterator(): 用于返回集合中元素的迭代器。
    6. boolean isEmpty():用于检查集合是否为空。返回true表示空,false表示非空条件。
    7. int size():用于返回集合的大小。
    8. Object clone():用于创建集合的浅表副本。
  •   Java 集合框架
  •   本文标题:Java中的HashSet的定义以及用法 - Break易站
    转载请保留页面地址:https://www.breakyizhan.com/java/4658.html
      微信返利机器人
      免费:淘宝,京东,拼多多优惠券
      腾讯,爱奇艺,优酷的VIP视频免费解析,免费看
      即刻扫描二维码,添加微信机器人!

    发表笔记

    电子邮件地址不会被公开。 必填项已用*标注