Java集合系列(9)--HashSet

21 篇文章 0 订阅
12 篇文章 0 订阅

前面我们已学习了ArrayList、LinkedList、HashMap、HashTable、TreeMap,接下来我们来学习HashSet。
首先我们对HashSet有一个整体的认识,然后学习它的源码,最后通过代码示例学会使用它。

一、HashSet基本概述

HashSet是由HashMap实现的,所以底层也是散列表(数组+链表)。
HashMap是无序的,且不允许元素重复,但HashSet允许元素为空。
HashSet是非同步的。如果多个线程同时访问一个HashSet,若其中至少一个线程修改了该set,那么就必须保持外部同步。这通常是通过封装该set的对象执行同步操作来完成的。
如果不存在这样的对象,则应该使用Collections.synchronizedSet(同步set)方法来包装set。在创建时完成该操作:

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

HashSet通过Iterator()返回的迭代器也是Fail-Fast机制。
易考点:

关注点结论
结合底层实现的数据结构由HashMap实现,散列表(数组+列表)
集合中元素是否允许为空Key和value都可以为空
是否允许数据重复不允许元素重复
是否有序无序,是指不是按put进来的顺序
是否线程安全非线程安全(不是同步的)
二、HashSet的数据结构

1>HashSet与Map关系如下图:
image
从中可以得到:
a.HashSet继承于AbstractSet,并且实现了Set接口;
b、HashSet不允许元素重复,底层是由HashMap实现的。HashSet中哈有一个HashMap类型的成员变量map,HashSet的操作函数,都是基于map实现的。
2>HashSet的构造函数
1、默认构造函数

// 默认构造函数
      public HashSet() {
          // 调用HashMap的默认构造函数,创建map
          map = new HashMap<E,Object>();
     }
2、带集合的构造函数
// 带集合的构造函数
    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);
    }
3、指定HashSet初始容量和加载因子的构造函数
 public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<E,Object>(initialCapacity, loadFactor);
    }
4、指定HashSet初始容量的构造函数
public HashSet(int initialCapacity) {
        map = new HashMap<E,Object>(initialCapacity);
    }
5、指定HashSet初始容量和加载因子的构造函数
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
    }
三、HashSet遍历方式
1、通过Iterator遍历HashSet
 HashSet set = new HashSet();
        Iterator iterator = set.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator);
        }
2、通过for-each增强for循环遍历HashSet
HashSet set = new HashSet();
String[] arr = (String[])set.toArray(new String[0]);
for (String str:arr)
    System.out.printf("for each : %s\n", str);
四、HashSet代码示例
package Test;

import java.util.HashSet;
import java.util.Iterator;

/**
 * Created by LKL on 2017/2/19.
 * HashSet常用API的使用。
 */
public class TestHashSet1 {
        public static void main(String[] args) {
            // HashSet常用API
            testHashSetAPIs() ;
        }

        /*
         * HashSet除了iterator()和add()之外的其它常用API
         */
        private static void testHashSetAPIs() {
            // 新建HashSet
            HashSet set = new HashSet();

            // 将元素添加到Setset.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");
        }
}

运行结果如下:

size : 5
HashSet contains a :true
HashSet contains g :false
for each : a
for each : b
for each : c
for each : d
removeset : [a, d]
retainset : [b, c]
iterator : a
iterator : b
iterator : c
iterator : d
set is empty

文章只是作为自己的学习笔记,借鉴了网上的许多案例,如果觉得阔以的话,希望多交流,在此
谢过…

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值