zoukankan      html  css  js  c++  java
  • java集合-HashSet源码解析

    HashSet 无序集合类

    • 实现了Set接口
    • 内部通过HashMap实现
    // HashSet
    public class HashSet<E>
        extends AbstractSet<E>
        implements Set<E>, Cloneable, java.io.Serializable
    {
        static final long serialVersionUID = -5024744406713321676L;
    
        //重要:HashMap HashSet就是通过HashMap保存数据, HashSet的值就是HashMap的key
        private transient HashMap<E,Object> map;  // 使用transient修饰不会被序列化
        
        //HashMap 为<key, value>的键值对, 既然HashSet的值就是HashMap的key, 那么HashMap的值呢,当然就是这个PRESENT,HashMap所有的value都是同一个对象
        private static final Object PRESENT = new Object();
        
        // 默认构造函数,创建一个HashMap对象
        public HashSet() {
            map = new HashMap<>();
        }
    
        //将一个已知的collection转换为HashSet
        public HashSet(Collection<? extends E> c) {
            //Collection<? extends E> c 限制了类型上限为E,也就是c只能是E类型或E的子类,防止参数是非Set类型
            //如果没有指定HashMap的capacity, 那么默认的就是16
            //根据 threshold = capacity * loadFactor, 可以计算出 capacity
            //Math.max((int) (c.size()/.75f) + 1, 16) 这个意思就是capacity如果没超过16, 那么就直接使用默认的16
            // 容量设置为4/3倍
            map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
            //将已知的collection转换为HashSet的方法
            //addAll方法是HashSet的父类AbstractCollection的方法,为了便于阅读,会将代码粘贴在下面
            addAll(c);
        }
        // 带有初始容量和因子的构造函数
        public HashSet(int initialCapacity, float loadFactor) {
            map = new HashMap<>(initialCapacity, loadFactor);
        }
    
    
        public HashSet(int initialCapacity) {
            map = new HashMap<>(initialCapacity);
        }
    
    
        HashSet(int initialCapacity, float loadFactor, boolean dummy) {
            map = new LinkedHashMap<>(initialCapacity, loadFactor);
        }
        
        //addAll方法是HashSet的父类AbstractCollection的方法
        public boolean addAll(Collection<? extends E> c) {
            boolean modified = false; // 只要添加了元素就返回true
            for (E e : c)
                //此处的add方法由HashSet重写实现
                if (add(e))
                    modified = true;
            return modified;
        }
        
        //HashSet的核心方法来了, 没错,就这么简单
        public boolean add(E e) {
            //应证了上面所说的key为HashSet的值
            return map.put(e, PRESENT)==null;
        }
        
        //剩下这些方法都是跟Map相关的了,只要熟悉了HashMap, 那就太简单了,就不说了
        public boolean remove(Object o) {
            return map.remove(o)==PRESENT;
        }
    
        public void clear() {
            map.clear();
        }
        
    }
    
    
    
    

    补充

    泛型

    泛型的上限通配符<? extends T>

    <? extends T>是 Upper Bound(上限) 的通配符,用来限制元素的类型的上限,比如  
    
    List<? extends Fruit> fruits;  
    表示集合中的元素类型上限为Fruit类型,即只能是Fruit或者Fruit的子类。
    

    泛型的下限通配符<? super T>

    <? super E> 是 Lower Bound(下限) 的通配符 ,用来限制元素的类型下限,比如
    
    List<? super Apple> apples;  
    表示集合中元素类型下限为Apple类型,即只能是Apple或Apple的父类。
    

    参考

  • 相关阅读:
    Leetcode95. Unique Binary Search Trees II不同的二叉搜索树2
    Leetcode134. Gas Station加油站
    Leetcode152. Maximum Product Subarray乘积的最大子序列
    C#扩展方法
    Lua语言入门
    Docker命令
    SpringBoot-配置文件属性注入-3种方式
    从零开始学Linux系统(五)用户管理和权限管理
    MyCat学习笔记
    kafka-zk-安装测试初体验
  • 原文地址:https://www.cnblogs.com/wang7/p/10146422.html
Copyright © 2011-2022 走看看