Java HashSet的去重问题

Java系列文章目录

补充内容 Windows通过SSH连接Linux
第一章 Linux基本命令的学习与Linux历史


一、前言

  • 使用HashSet对类对象去重失败

二、学习内容:

  • HashSet去重的原理

三、问题描述

  • 当参数是一个类的时候

在这里插入图片描述

  • HashSet无法去重

输出还是两条一样的

在这里插入图片描述


四、解决方案:

4.1 部分功能概况

  • HashSet部分功能

在这里插入图片描述

在这里插入图片描述

4.2 问题原因与解决

Object里面的equals方法默认比较的就是地址值,t1和t2的地址值不一致,所以HashSet认为这是两个不同的对象,所以我们需要重写方法。

重写 hashCode() 和 equals() 方法与 HashSet 的去重机制密切相关。

  • 在 Java 中,HashSet 是基于 HashMap 实现的一个不包含重复元素的集合。当向 HashSet添加一个对象时,它首先计算该对象的哈希码 (hashCode()),然后使用该哈希码来确定对象在哈希表中的位置。如果两个对象的哈希码相同,那么它们可能会映射到同一个桶(bucket)中。

重写方法:
解决方法
在这里插入图片描述

hashCode() 方法:

  • 应该返回一个整数值,这个值是对象的一个哈希码。
  • 如果两个对象相等(即 equals() 返回 true),那么它们的 hashCode() 必须返回相同的值。
  • 如果两个对象不相等,它们的 hashCode() 方法返回的值不一定不同,但是不同的哈希码有助于提高哈希表的性能。

equals() 方法:

  • 用来判断两个对象是否相等。
  • 如果 equals() 方法返回 true,那么两个对象的 hashCode() 方法应该返回相同的值。
  • 如果 equals() 方法返回 false,那么 hashCode() 方法的返回值可以相同或不同。

源码具体实现:
在这里插入图片描述

  • 其中 hash(key) 方法会调用 key.hashCode() 来获取哈希码。putVal方法则负责实际的插入操作,它会检查是否有哈希码相同的键存在,如果有,则会调用 equals 方法进一步确认键是否相等。

五、总结:

5.1 学习总结:

  • Object中是比较值所以可以去重但是对象要重写方法
  • 注意需要重写两个方法才能去重

在 HashSet 中,当添加一个新对象时,如果发现有哈希码相同的对象,就会进一步调用 equals() 方法来进行比较。这个过程发生在 HashMap 的 put 方法中,因为 HashSet 实际上是基于 HashMap 实现的。

HashSet 的 add 方法:

   public boolean add(E e) {
       return map.put(e, PRESENT) == null;
   }
  • 这里 map 是 HashSet 内部的 HashMap,PRESENT 是一个静态对象,用于标记 HashSet 中的元素。

HashMap 的 put 方法:

   public V put(K key, V value) {
       return putVal(hash(key), key, value, false, true);
   }
   
  • 这里的 hash(key) 方法会调用 key.hashCode() 来获取哈希码。

HashMap 的 putVal 方法:

   final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                  boolean evict) {
       Node<K,V>[] tab; Node<K,V> p; int n, i;
       if ((tab = table) == null || (n = tab.length) == 0)
           n = (tab = resize()).length;
       if ((p = tab[i = (n - 1) & hash]) == null)
           tab[i] = newNode(hash, key, value, null);
       else {
           Node<K,V> e; K k;
           if (p.hash == hash &&
               ((k = p.key) == key || (key != null && key.equals(k))))
               e = p;
           else if (p instanceof TreeNode)
               e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
           else {
               for (int binCount = 0; ; ++binCount) {
                   if ((e = p.next) == null) {
                       p.next = newNode(hash, key, value, null);
                       if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                           treeifyBin(tab, hash);
                       break;
                   }
                   if (e.hash == hash &&
                       ((k = e.key) == key || (key != null && key.equals(k)))) {
                       break;
                   }
                   p = e;
               }
           }
           if (e != null) { // existing mapping for key
               V oldValue = e.value;
               if (!onlyIfAbsent || oldValue == null)
                   e.value = value;
               afterNodeAccess(e);
               return oldValue;
           }
       }
       ++modCount;
       if (++size > threshold)
           resize();
       afterNodeInsertion(evict);
       return null;

   
  • 在这里,可以看到当 HashMap 的 put方法被调用时,它会首先计算哈希码,然后定位到相应的桶(bucket)。如果桶中已经有哈希码相同的对HashMap会遍历桶中的链表,并对每个对象调用 key.equals(k) 方法来进行比较。

equals 方法的调用:

  • 如果桶中的某个对象的哈希码与新对象的哈希码相同,HashMap 会调用 key.equals(k)方法来进一步确认这两个对象是否相等。如果 equals 方法返回 true,那么 HashMap认为这两个对象是相等的,因此不会添加新对象。如果 equals 方法返回 false,则认为这两个对象是不相等的,新对象会被添加到桶中。

(后续有遇到问题再添加)


声明:如本内容中存在错误或不准确之处,欢迎指正。转载时请注明原作者信息(麻辣香蝈蝈)。

  • 18
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值