mutable.Set的特性,以及自定义类中equals和hashCode方法对集合去重逻辑的影响

scala 复制代码
package caseclass

import scala.collection.mutable

object caseclass1 {
   class Book(var id: Int, var name: String) {
     override def equals(obj: Any): Boolean = {
       val other = obj.asInstanceOf[Book]
       other.id == id && other.name == name
     }

     override def hashCode(): Int = id
   }
    def main(args: Array[String]): Unit = {
      val set1: mutable.Set[Int] = mutable.Set(1, 2)


      set1 += 1
      set1 += 1
      set1 += 1
      set1 += 1
      println(set1)

      val book1 = new Book(1, "西游记")
      val book2 = new Book(1, "西游记")

      println(book1 == book2)

      //定义一个set,它的类型是Book,它可以装入的数据是book类型
      val set2: mutable.Set[Book] = mutable.Set()
      set2 += book1
      set2 += book2

      println(set2)
    }
  }

这段 Scala 代码主要演示了可变集合mutable.Set的特性,以及自定义类中equalshashCode方法对集合去重逻辑的影响,具体分析如下:

代码功能与执行结果

  1. 整数集合去重 :定义mutable.Set[Int]类型的set1,初始包含12,多次添加1后,集合仍为Set(1, 2)。因为Set的特性是自动去重,整数类型的相等性判断基于值,重复元素会被自动忽略。
  2. 自定义类对象的相等性 :自定义Book类重写了equals方法(通过idname判断相等)和hashCode方法(基于id生成哈希值)。创建book1book2idname均相同),book1 == book2输出true,符合重写...

解释

这段 Scala 代码主要围绕可变集合mutable.Set的去重逻辑自定义类的equalshashCode方法重写展开,我们逐部分拆解解释:

1. 整数集合的去重演示

scala

arduino 复制代码
val set1: mutable.Set[Int] = mutable.Set(1, 2)
set1 += 1
set1 += 1
println(set1)  // 输出:Set(1, 2)
  • Set(无论可变 / 不可变)的核心特性是元素唯一性,会自动过滤重复元素。
  • 这里多次向set1添加1,但最终集合仍只保留一个1,因为整数类型(Int)的相等性判断是基于值本身 的,1 == 1始终成立,所以重复添加无效。

2. 自定义类BookequalshashCode重写

scala

kotlin 复制代码
class Book(var id: Int, var name: String) {
  // 重写equals:通过id和name判断两个Book对象是否相等
  override def equals(obj: Any): Boolean = {
    val other = obj.asInstanceOf[Book]  // 将Any类型强转为Book
    other.id == id && other.name == name
  }

  // 重写hashCode:基于id生成哈希值
  override def hashCode(): Int = id
}
  • equals方法 :默认情况下,类的equals是基于对象引用 的(即两个对象必须是内存中同一个实例才相等)。这里重写后,只要两个Book对象的idname相同,就判定为相等(book1 == book2返回true)。
  • hashCode方法 :哈希值是集合(如Set)存储元素时的 "快速索引",Set会先通过hashCode分组,再对同组元素用equals判断是否重复。这里hashCode基于id生成,意味着id相同的Book对象会被分到同一组。

3. Book对象存入Set的 "看似矛盾" 现象

scala

ini 复制代码
val book1 = new Book(1, "西游记")
val book2 = new Book(1, "西游记")
println(book1 == book2)  // 输出:true

val set2: mutable.Set[Book] = mutable.Set()
set2 += book1
set2 += book2
println(set2)  // 输出:Set(Book@1, Book@1)(看似重复,实际是两个不同实例)
  • book1 == book2true :因为我们重写了equalsbook1book2idname都相同,所以相等性判断成立。

  • set2中同时存在book1book2 :这是关键的 "矛盾点"------ 明明book1 == book2true,但Set却没有去重?原因在于:Set的去重逻辑依赖 hashCodeequals的协同 ,且对于普通类 (非样例类),即使重写了equalshashCodeSet仍会结合对象引用辅助判断(或因 JVM 的哈希碰撞处理细节)。更本质的是:

    • book1book2两个不同的对象实例 (内存地址不同),而mutable.Set对普通类的去重逻辑,在hashCode相同、equalstrue时,仍可能因 "实例唯一性" 保留多个对象(这是普通类与样例类的核心区别)。

4. 为什么用样例类(case class)就能正确去重?

如果将Book定义为样例类

scala

javascript 复制代码
case class Book(var id: Int, var name: String)  // 无需手动重写equals/hashCode

此时set2 += book1; set2 += book2会输出Set(Book(1,西游记)),因为样例类会自动生成基于构造参数的equalshashCode ,完全遵循 "值相等即对象相等" 的逻辑,Set会正确识别重复并去重。

总结

  • Set的去重依赖hashCode(分组)和equals(判重)的协同。
  • 普通类需手动重写equalshashCode,但仍可能因 "实例引用" 导致Set去重失效;样例类自动实现正确的equalshashCode,是 Scala 中实现 "值相等" 的推荐方式。
  • 整数等基础类型的equalshashCode已默认实现 "值相等",因此Set对基础类型的去重始终有效。
相关推荐
悟空码字1 小时前
Kubernetes实战:你的分布式系统“保姆”养成记
java·后端·kubernetes
刃神太酷啦1 小时前
C++的IO流和C++的类型转换----《Hello C++ Wrold!》(29)--(C/C++)
java·c语言·开发语言·c++·qt·算法·leetcode
稚辉君.MCA_P8_Java1 小时前
Gemini永久会员 哈希表(Hash Table)高效的数据结构
java·数据结构·后端·算法·架构
一只乔哇噻1 小时前
java后端工程师+AI大模型进修ing(研一版‖day58)
java·开发语言
lichong9511 小时前
Android 弹出进度条对话框 避免用户点击界面交互
java·前端·javascript
Geek__19921 小时前
杂记:记录一次Sqlite的使用问题
java·oracle·sqlite
summer__77771 小时前
【期末复习01】-算法题ProgramDesign
java·算法
x***38161 小时前
比较Spring AOP和AspectJ
java·后端·spring
CoderYanger1 小时前
递归、搜索与回溯-记忆化搜索:40.矩阵中的最长递增路径
java·线性代数·算法·leetcode·矩阵·1024程序员节