zoukankan      html  css  js  c++  java
  • 【java集合框架源码剖析系列】java源码剖析之HashSet

    注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本。本博客将从源码角度带领大家学习关于HashSet的知识。

    一HashSet的定义:

    public class HashSet<E>
        extends AbstractSet<E>
        implements Set<E>, Cloneable, java.io.Serializable
    可以看到HashSet继承自AbstractSet同时实现了Set,Cloneable,Serializable三个接口,其中Cloneable,Serializable这两个接口基本上是java集合框架中所有的集合类都要实现的接口。

    二HashSet中的重要属性:

    <strong>  </strong>private transient HashMap<E,Object> map;
      private static final Object PRESENT = new Object();
    
    
    可以看到HashSet中的属性非常少,其中第一个属性是HashMap对象,是HashSet中用来存储数据的,据此可知HashSet的底层是基于HashMap的,关于HashMap的详细讲解请参看我的博客:【java集合框架源码剖析系列】java源码剖析之HashMap,而第二个属性表示的是HashSet中HashMap实例的value,因为HashSet虽然底层是基于HashMap实现的,但是HashSet只用来存储Key,其Value是无意义,Value的值全部用第二个属性代替。

    三HashSet内部的实现原理:我们来看一下其构造器

     public HashSet() {
            map = new HashMap<>();
        }
    
     public HashSet(Collection<? extends E> c) {
            map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
            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);
        }
    
    
    可以看到HashSet供5个构造器,其中前四个都是在其内部创建一个HashMap的实例,(从这里更清楚的看到HashSet的底层是基于HashMap的)而第5个则是创建一个LinkedHashMap的实例,而且第5个构造器前面无public修饰,表明该构造器对外不公开,事实上仅仅供LinkedHashSet使用的。第二个构造器表明当使用一个集合c作为参数来构造一个HashSet的时候会调用addAll(c),我们来看一下其源码:

     public boolean addAll(Collection<? extends E> c) {
            boolean modified = false;
            for (E e : c)
                if (add(e))
                    modified = true;
            return modified;
        }
    
     public boolean add(E e) {
            return map.put(e, PRESENT)==null;
        }
    

    可以看到在addAll中调用了add(),而在add(E)方法中可以清楚看到使用HashMap的put方法时第二个参数传入的都是PRESENT,这就说明了HashSet中只保存Key而不保存Value。

    四HashSet中的重要方法:

     public boolean add(E e) {
            return map.put(e, PRESENT)==null;
    
        }
    
    public boolean remove(Object o) {
            return map.remove(o)==PRESENT;
        }
    
     public void clear() {
            map.clear();
        }
    
    
    可以看到HashSet中与HashMap中同名的方法全部都是调用的HashMap中的方法来实现的。

    五总结:经过前面HashMap的源码剖析可以看到HashSet非常简单

    1HashSet底层是基于HashMap的,但是仅仅用来保存Key,而不保存Value,因为HashSet的add()方法在调用HashMap的put方法的时候第二个参数传入的都是PRESENT这个固定的Object对象。

    2可以看到HashSet中的add与remove等方法均无synchronized关键字修饰,即HashSet不是线程安全的,如果要使用同步的HashSet需要使用Collections集合类的静态方法,即Set s=Collections.synchronizedSet(new HashSet());

    3HashSet中的值允许为null,因为HashSet底层是基于HashMap的,而HashMap允许插入null。

    4HashSet中的元素不允许重复,因为HashSet底层是基于HashMap的,而HashMap不允许存在重复元素,因为在put时如果key相同则会替换之前的V值。

  • 相关阅读:
    excel中年月日格式的数据分离出年
    Vision MLP 之 Sparse-MLP A Fully-MLP Architecture with Conditional Computation
    Vision MLP 之 S2-MLP V1&V2 : Spatial-Shift MLP Architecture for Vision
    Visoin MLP之CycleMLP A MLP-like Architecture for Dense Prediction
    Vision MLP之RaftMLP Do MLP-based Models Dream of Winning Over Computer Vision
    Vision MLP之Hire-MLP: Vision MLP via Hierarchical Rearrangement
    显著性目标检测之Learning to Promote Saliency Detectors
    paddle中的LoDTensor
    C语言0长度数组(可变数组/柔性数组)
    1、迭代器失效
  • 原文地址:https://www.cnblogs.com/hainange/p/6334036.html
Copyright © 2011-2022 走看看