在Scala中,针对case class和"非case" class的区别是什么?

5

我是一名学习Scala的人,遇到了以下难题。

我可以定义以下case类:

abstract class Expr
case class Number(n: Int) extends Expr

当我从类Number创建两个实例并进行比较时
val x1 = Number(1)
val x2 = Number(1)
x1 == x2

我有以下结果:

x1: Number = Number(1)

x2: Number = Number(1)

res0: Boolean = true

因此,x1x2是相同的。

然而,如果我在Number类定义中删除case修饰符,即

abstract class Expr
class Number(n: Int) extends Expr

然后以相同的方式比较两个Number类的实例

val x1 = new Number(1)
val x2 = new Number(1)
x1 == x2

我有以下输出:
x1: Number = Number@1175e2db x2: Number = Number@61064425 res0: Boolean = false 这里表明,这一次 x1 和 x2 是不同的。
你能告诉我为什么吗?在比较两个实例方面,case 有什么区别呢?
谢谢, Pan

抱歉,我错误地创建了 val x2 = Number(2),实际上应该是 val x2 = Number(1)。我已经更正了它。 - panc
1个回答

11
在Scala中定义一个case class时,编译器会生成一个equals方法来检查深度相等(即类的内容)。当你去掉case关键字时,你生成了常规类,对它们进行==比较将检查引用(浅)相等性。由于你在比较类的两个唯一实例,它们虽然内容相同但却不满足引用相等性。
参见浅相等和深相等的区别:什么是浅相等和深相等?如何应用于缓存?
来源:http://www.scala-lang.org/old/node/107

2
为了精确起见,调用==并不会强制进行引用相等性检查,它实际上会调用您可以重写以执行任何操作的equals方法。引用相等性只是普通类的默认实现,可以通过eq方法强制进行引用相等性检查。这种==的行为与Java中的行为不同。 - PermaFrost
通常,“浅”和“深”这两个词的用法与本答案不同。普通类不会覆盖equals()方法,而默认实现是“引用”相等性,即比较对象本身的引用。Case类比较它们的字段是否相等,但是它们将比较委托给字段的equals()方法,如果以相同方式定义,则导致深度相等,但如果没有,则导致浅层相等(仅1级深度)。https://en.wikipedia.org/wiki/Object_copying#Shallow_copy - Konstantin Pelepelin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接