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对基础类型的去重始终有效。
相关推荐
PP东2 分钟前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable
ManThink Technology7 分钟前
如何使用EBHelper 简化EdgeBus的代码编写?
java·前端·网络
invicinble12 分钟前
springboot的核心实现机制原理
java·spring boot·后端
人道领域20 分钟前
SSM框架从入门到入土(AOP面向切面编程)
java·开发语言
大模型玩家七七40 分钟前
梯度累积真的省显存吗?它换走的是什么成本
java·javascript·数据库·人工智能·深度学习
CodeToGym1 小时前
【Java 办公自动化】Apache POI 入门:手把手教你实现 Excel 导入与导出
java·apache·excel
凡人叶枫1 小时前
C++中智能指针详解(Linux实战版)| 彻底解决内存泄漏,新手也能吃透
java·linux·c语言·开发语言·c++·嵌入式开发
JMchen1232 小时前
Android后台服务与网络保活:WorkManager的实战应用
android·java·网络·kotlin·php·android-studio
阔皮大师2 小时前
INote轻量文本编辑器
java·javascript·python·c#
小法师爱分享2 小时前
StickyNotes,简单便签超实用
java·python