源码分析之HashSet

概念

HashSetJava Collections FrameworkSet接口的一种实现了。HashSet底层是基于HashMap来实现的,之前已经分析过HashMap的源码,这时候再来看HashSet的源码相对来说是很轻松的。

类结构

HashSet继承AbstractSet类,实现了Set接口。由于HashSet是用HashMap实现的,所以HashMap在数据存储上也是无序的。

类成员

PRESENT

   private static final Object PRESENT = new Object();

HashMap是键值对K-V模型的,HashSet则是普通的集合类型。这里的PRESENT就是用来填充HashMap中的value的。

构造函数

HashSet提供了4种构造函数。


    // 默认无参构造函数
    public HashSet() {
        map = new HashMap<>();
    }
    
    // 以现有集合构造
    public HashSet(Collection<? extends E> c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }
    
    // 带参构造 initialCapacity: 初始大小  loadFactor:加载因子
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<>(initialCapacity, loadFactor);
    }
    // 带参构造 initialCapacity: 初始大小
    public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }
    
    // 仅用来构造LinkedHashSet使用
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }

add 方法

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

add方法很简单,直接调用HashMapput方法实现。value则是用PRESENT进行填充。

remove 方法

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

remove方法也是同样,调用HashMapremove方法。

...

HashSet大多数的方法都是通过HashMap的方法来实现的。

hashCode方法 & equals方法

如果我们在使用HashSet来存储自定义的对象时候,要记得重写hashCode方法和equals方法。我们将通过一个示例来说明重写的必要性。

public class Test {

    String a;

    public Test(String a) {
        this.a = a;
    }
    
    public static void main(String[] args) {

        Set set = new HashSet();

        Test o1 = new Test("abc");
        Test o2 = new Test("abc");

        set.add(o1);
        set.add(o2);

        System.out.println(o1.equals(o2));
        System.out.println(set.size());

    }

上面程序输出应该是:

false
2

默认equals方法是通过比较引用是否来判断2个对象是否一致的。o1o2显然是2个对象,他们是不相等的,他们各自的hashcode显然是不同的,所以HashSet会把他们当做2个不同对象来处理。

我们想要a相同的对象都是同一个对象的话,使用默认的equalshashcode方法显然无法满足我们要求的,这时候就需要重写equalshashcode方法。

    @Override
    public int hashCode() {

        return 123 * 31 + a.hashCode();
    }

    @Override
    public boolean equals(Object o) {

        Test test = (Test) o;
        return test.a.equals(this.a);
    }

这里再运行main的结果就是:

true
1

总结

HashSet存储元素,是将元素作为HashMapkey进行操作,所以不保证元素顺序。HashSet不会有重复数据,重复数据都被覆盖。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、基本数据类型 注释 单行注释:// 区域注释:/* */ 文档注释:/** */ 数值 对于byte类型而言...
    龙猫小爷阅读 4,297评论 0 16
  • 实际上,HashSet 和 HashMap 之间有很多相似之处,对于 HashSet 而言,系统采用 Hash 算...
    曹振华阅读 2,532评论 1 37
  • 本文出自 Eddy Wiki ,转载请注明出处:http://eddy.wiki/interview-java.h...
    eddy_wiki阅读 1,189评论 0 16
  • Java8张图 11、字符串不变性 12、equals()方法、hashCode()方法的区别 13、...
    Miley_MOJIE阅读 3,759评论 0 11
  • java笔记第一天 == 和 equals ==比较的比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量...
    jmychou阅读 1,532评论 0 3