Yes, they are merged, but there’s a special rule - if there’s an explicitly defined method then compiler doesn’t provide its own generated definition. So e.g. case class X(a: Int, b: String)
expands to:
class X(val a: Int, val b: String) {
def equals ...
def hashCode ...
def toString ...
...
}
object X {
def apply(a: Int, b: String): X = X(a, b)
def unapply ...
}
but if you e.g. provide your own toString
then your implementation won’t be replaced by autogenerated one:
case class X(a: Int, b: String) {
override def toString(): String =
"hey, this method is explicitly defined so compiler won't regenerate it!"
}
This rule applies to both class
and it’s companion object
.
We’ve already used that rule here: What does Equivalence of instances mean? - #11 by tarsa to provide own equals
and hashCode
definitions instead of the auto-generated ones.
If you look at generated .class files then you’ll notice that object Xxx
compiles to two files: Xxx.class
and Xxx$.class
. OTOH class Xxx
compiles to just Xxx.class
. So every time you have a class
(no matter if case
or not) with its companion object
the Xxx.class
contains definitions related to both class
and object
. In other words - merging happens quite often.