HashSet去重原理

HashSet去重原理

首先我们来说说HashSet的特点:

  • 它是无序的,即添加的顺序和遍历出来的顺序是不同的
  • 它里面不允许有重复元素,是因为它是基于HashMap实现的
  • 实现了Set接口,由哈希表(实际上是一个HashMap实例)支持
  • 底层数据结构是哈希表

那它是如何保证元素的唯一性的呢?

答案是依赖两个方法:
hashCode()equals()方法

如果我们希望一个集合有去重复的功能, 可以在它的add方法中检查要添加的对象在集合中是否存在,迭代集合中每个元素, 和要添加的比较, 如果相同, 就不存,所以我们来看看add()方法的部分源码解析:
因为源码太长,我就截取一小部分重要的出来哈!

private static final Object PRESENT = new Object();
private transient HashMap<E,Object> map;    
public boolean add(E e) { 
            return map.put(e, PRESENT)==null;
}    
......
if (e.hash == hash && ((k = e.key) == key || key.equals(k))){
......//e.hash调用了hashCode()方法获得了e元素的hash值
}

从源码中我们可以看出:
它的add()方法实际上调用的是HashMap中的put()方法,把要添加进HashSet中的元素当做key存入,而value则是一个固定值:一个Object类对象。
先用hashCode()方法获得传入元素的哈希值,在集合中查找是否包含哈希值相同的元素,如果相同,则继续进行比较它们地址值,一般地址值都是不相同的,所以最后会用equals()方法比较对象内的属性值。
比较结果全为false就存入,如果比较结果有true则不存.

那如何将自定义类对象存入HashSet进行去重呢?


  • 类中必须重写hashCode()方法和equals()方法
  • equals()方法中比较所有属性
  • hashCode()方法要保证属性相同的对象返回值相同, 属性不同的对象尽量不同,对象的成员变量值相同即为同一个元素

我用了一个Student类进行说明,类中有name和age属性:
>重写后的hashCode()方法:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}

要尽可能的让不同对象的哈希值不相同,因为使用equals()方法进行一系列的判断的前提是要建立在哈希值相同的基础上的,如果哈希值不相同,就直接添加该元素,就不用进行后续的判断了,这样就节省了好多资源;
那怎样保证hash值尽量不相同呢?
由重写后的hashCode()方法可以看出:成员变量的值影响了哈希值,所以我们把成员变量的值和哈希值做一系列的运算,更改后相加即可,例如我们可以把它们乘以一些整数
重写后的equals()方法:

@Override
    public boolean equals(Object obj) {
        if (this == obj)     //先判断传入的对象地址是否和当前对象一样
          return true;     //如果一样的话,肯定为同一对象,直接返回true
        if (obj == null)       //如果传入的对象为空的话
          return false; //则直接返回false,添加到集合中,因为Set可以存null值
        if (getClass() != obj.getClass())//然后判断字节码文件的对象
          return false;//不相等的话说明两个元素肯定不同,就直接返回false
        Student other = (Student) obj;    //然后进行成员变量的比较
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

HashSet去重原理总结:

A:HashSet底层数据结构是哈希表(是一个元素为链表的数组)
B:哈希表底层依赖两个方法:hashCode()和equals()

执行顺序:
    首先比较哈希值是否相同
        相同:继续执行equals()方法
               返回true:元素重复了,不添加
               返回false:直接把元素添加到集合
        不同:就直接把元素添加到集合

C:元素唯一性由hashCode()和equals()保证的,二者缺一不可


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值