对于两个逻辑上相等的实例,具有非原语的 case 类的 equals 不能正常工作

问题描述

对于两个逻辑上相等的 case 类实例,Equals 无法正常工作。 请在下面找到简化的案例类:-

case class Item(name : String)
case class Basket(items : Array[Item],bills : Map[Int,Int])

def createBasketInstance() : Basket = {
  val maggi = Item("milk")
  val coffee = Item("coffee")

  val bills1 = Map(1 -> 20,2 -> 75)
  Basket( Array(maggi,coffee),bills1 )
}

val basket1 = createBasketInstance()
val basket2 = createBasketInstance()

basket1.equals(basket2) 的预期结果为真,但实际打印为假。

scalafiddle 链接https://scalafiddle.io/sf/iJRKnMk/0

请找到附加的屏幕截图,以确认使用 Scalatest 进行相等比较。

enter image description here

解决方法

这与 equals 的默认 case classes 无关,而是 Arrays 的默认 Lists(这是您应该使用 Arrays 而不是 { {1}}顺便说一句)

在 Scala 中数组只是普通的 Java 数组,Java 中的数组被特殊处理(因为 JVM)

即使是简单的

Array(1,2,3) == Array(1,3)

将返回 false。

为什么?因为数组继承了 Object.equals 方法的 equals 只比较了数组引用,而不是它们的内容。

我知道这听起来没有那么糟糕,但相信情况会变得更糟。

您可能认为简单地将数组分配给一个值就可以解决问题,对吗?好吧,它没有。以下也将失败...

def createBasketInstance() : Basket = {
  val maggi = Item("milk")
  val coffee = Item("coffee")
  val arr =  Array(maggi,coffee)
  val bills1 = Map(1 -> 20,2 -> 75)
  Basket( arr,bills1 )
}

因为这个函数的不同调用的调用栈不能共享引用,因此即使底层内容相同,每次函数调用都会创建一个新的引用。

你是如何解决这个问题的?

  1. java.utils.Arrays 中有一个名为 Arrays.equals 的方法可以进行深度比较。您可以 override 并构造它,以便比较使用 Arrays.equals。您可能还需要覆盖 hashCode

  2. 编写从 Array 到几乎任何其他集合的隐式转换

  3. 首先不要使用数组。

我想说 #3 是解决这个问题的方法

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...