• HashSet源码解析-Java8


    目录

    一.HashSet介绍

    二.HashSet源码分析

      2.1 HashSet原理概览

      2.2 HashSet的属性

      2.3 构造方法

      2.4 add操作

      2.5 contains操作

      2.6 remove操作

      2.7 size操作

    三.总结

    一.HashSet介绍

      对于HashSet,用不着太多的介绍,可以先看一个简单的算法题:有一个数组,需要在O(n)的时间复杂度内,找出哪些数据是重复的。

      上面这个问题,没有限制空间复杂度,则可以使用Map来完成,像下面这样做:

    public List<String> findDuplicateData(String[] arr) {
        List<String> res = new ArrayList<>();
        Map<String, Boolean> map = new HashMap<>();
    
        for (String str : arr) {
            if (map.get(str) != Boolean.TRUE) {
                // 如果map中已经存在该str,则表示重复了,将其加入结果集合中
                res.add(str);
    
            } else {
                // 如果map中不存在str,则将其加入map,value为Boolean.TRUE
                map.put(str, Boolean.TRUE);
            }
        }
    
        return res;
    }
    

      上面在使用map的时候,可以看到,其实Map的value都始终都是Boolean.TRUE,这个时候,设置value其实很多余。

      这个时候就可以使用HashSet来完成,相对来说更加好理解:

    public List<String> findDuplicateData(String[] arr) {
        List<String> res = new ArrayList<>();
        Set<String> set = new HashSet<>();
    
        for (String str : arr) {
            if (set.contains(str)) {
                // 如果集合中已经存在该str,则表示重复了,将其加入结果集合中
                res.add(str);
    
            } else {
                // 如果集合中不存在str,则将其加入集合
                set.add(str);
            }
        }
    
        return res;
    }
    

      其实对于HashSet,并没有太多需要介绍的,他的特点如下:

      1.增删改查set中的元素,时间复杂度都为O(1);

      2.不会出现重复元素;

      3.顺序是不确定的;

      这些特点通过后面看了HashSet的源码,也就明白了。

    二.HashSet源码解析 

    2.1 HashSet的原理概览

      先简单的对HashSet的原理提一下,方便后面对源码的理解。

      HashSet内部其实是基于HashMap的,上面我们使用map来完成put操作,value需要自定义;而在HashSet中,value是常量(一个Object对象)。

    2.2 HashSet的属性

      HashSet其实就只有两个属性,一个是map属性,用来保存HashSet.add()的数据;add的数据作为map的key,value则是PRESENT常量(一个普通Object对象)。

    /**
     * 存放数据的map
     */
    private transient HashMap<E,Object> map;
    
    /**
     * map属性在put时的value
     */
    private static final Object PRESENT = new Object();
    

      

    2.3 构造方法

      HashSet的构造方法,做的主要工作就是初始化map属性,将其赋值为一个HashMap。  

    /**
     * 实例化HashSet,并且创建HashMap(使用默认初始容量16和默认负载因子0.75)
     */
    public HashSet() {
        map = new HashMap<>();
    }
    
    /**
     * 实例化HashSet,并且创建HashMap(使用自定义的初始容量和默认的负载因子0.75)
     */
    public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }
    
    
    /**
     * 实例化HashSet,并且创建HashMap(使用自定义的初始容量和负载因子)
     */
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<>(initialCapacity, loadFactor);
    }
    
    /**
     * 实例化HashSet,并且创建HashMap(使用自定义的初始容量和负载因子)
     * 第3个参数时dummy(傀儡),如果有自己的额外需求,可以修改源码进行定制化
     */
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }
    

      

    2.4 add操作

      HashSet.add()接口,将新元素加入到set集合中,内部其实是加入到HashMap中。

    /**
     * 加入一个元素到set中(其实是加入到HashSet的map属性中)
     * 
     * @return true:set不包含该元素; false:set已经包含该元素
     */
    public boolean add(E e) {
        // 调用HashMap的put方法,也就是将加入的元素作为key,PRESENT常量作为value
        return map.put(e, PRESENT) == null;
    }
    

      

    2.5 contains操作

    /**
     * 判断元素是否存在于set集合中,内部其实是调用map的接口,判断是否存在该key的节点
     */
    public boolean contains(Object o) {
        return map.containsKey(o);
    }
    

      

    2.6 remove操作

    /**
     * 从set集合中移除某个元素,实际是移除HashMap中key为该元素的节点
     * 
     * @return true:成功移除元素; false:移除元素失败(未找到要移除的元素)
     */
    public boolean remove(Object o) {
        return map.remove(o) == PRESENT;
    }
    

      

    2.7 size操作

    /**
     * 返回set中的元素个数(也就是返回HashMap中的元素个数)
     */
    public int size() {
        return map.size();
    }
    

      

    三.总结

      看了上面HashSet的源码,其实可以发现,HashSet其实就是利用HashMap,在HashMap上套了一层壳。使用HashMap也能完成HashSet的工作,但是HashSet在某些时候对于代码的可读性更加好。

      原文地址:https://www.cnblogs.com/-beyond/p/13428580.html

      

  • 相关阅读:
    中国历史年代史的一些总结-缕清上下五千年
    struts2 自己定义表单
    &quot;What&#39;s New&quot; WebPart in SharePoint
    Tomcat+Servlet登录页面实例
    JAVA原始的导出excel文件,快捷通用 方便 还能够导出word文档哦
    Android开发 -- Bootloader
    NorFlash、NandFlash、eMMC比较区别【转】
    strspn() 和 strcspn() 函数【转】
    Device Tree(一):背景介绍【转】
    设备树使用手册【转】
  • 原文地址:https://www.cnblogs.com/-beyond/p/13428580.html
Copyright © 2020-2023  润新知